Customizing the entity in the entity framework - entity-framework

I have the following problem: I have a table in the database called Person which have all the relevant data such as first name, last name, date of birth, sex etc ... . My question is : Is it possible to hide some of the attributes and if yes how can i achieve that. I need that because in my entity instead of date of birth I want an attribute called age which will take the date of birth and calculate the age. Also I want to hide another column called job which has default value N for no and also can be Y for yes. Instead of it I want to have the same column but with true or false. I know that I can achieve that changing the database but in my case I am not allowed to do that. And the last point: is there away to add additional columns which doesn't have a representation in the database ..for example a computed one which takes the attribute salary and based on it (for example if it is more or less than 500 euros) calculates the bonuses ? Thanks :)

Place your context and entities into a seperate project. The Person entity you've described could be done as follows:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
internal DateTime DateOfBirth { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public double AgeInYears { get { return DateTime.Now.Subtract(this.DateOfBirth).TotalDays / 365; } }
public char Sex { get; set; }
internal string Job { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public bool HasJob { get { return this.Job == "Y"; } }
}
Doing the above will only expose FirstName, LastName, AgeInYears, Sex, and HasJob to other projects, in the datatype you want.
To add a column that doesn't exist in the database, just use the appropriate Data Annotation as shown above.
To hide a column, mark it as internal.
Hope that helps.

Related

Cannot insert explicit value for identity column - into related table

I have a database first model.
My application UI provides a group of checkboxes, one for each value in Data_Type.
When the user checks one, I expect a row to be added in BUS_APPL_DATA_TYPE,
however I'm getting an error about Cannot insert explicit value for identity column in DATA_TYPE (And I absolutely do not actually want to insert data in this table)
My EF Model class for BUS_APPL has this property
public ICollection<BusApplDataType> BusApplDataType { get; set; }
And that EF Model class looks like
public partial class BusApplDataType
{
public int BusApplId { get; set; }
public int DataTypeId { get; set; }
[Newtonsoft.Json.JsonIgnore]
public BusAppl BusAppl { get; set; }
public DataType DataType { get; set; }
}
What exactly do I need to add to the BusApplDataType collection to get a record to be inserted in BUS_APPL_DATA_TYPE?
Edit:
At a breakpoint right before SaveChanges.
The item at index 2 is an existing one and causes no issues.
The item at index 3 is new. Without this everything updates fine. There is a DATA_TYPE with id 5 in the database.
The surrounding code, if it helps.
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody] BusAppl item)
{
...
var existing = _context.BusAppl.FirstOrDefault(t => t.Id == id);
...
existing.BusApplDataType = item.BusApplDataType; //A bunch of lines like this, only this one causes any issue.
...
_context.BusAppl.Update(existing);
_context.SaveChanges();
return new NoContentResult();
}
My issue was that I needed to use my context to look up the actual entity, using info passed, instead of using the one with all the same values that was passed into my api directly.

Entity Framework identity column always zero

I'm using following class to insert products to database.
ID column is primary key.
After adding multiple products to db context (without calling savechanges method) all newly added rows identity columns are zero!
My scene...
User adds several products and browse them on the data grid.
User selects one product and adds some barcodes to selected product.
When user finishes the job clicks on save button and application calls SaveChanges method!
When user wants to add some barcodes to products firstly I need to find selected product from context and adds entered barcode text to Barcodes list. But I cant do that because all products identity columns value are the same and they are zero.
How can I solve this problem?
public class Product
{
public int ProductID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public virtual List<Barcode> Barcodes { get; set; }
}
public class Barcode
{
public int BarcodeID { get; set; }
public string BarcodeText { get; set; }
public int ProductID { get; set; }
public virtual Product Product { get; set; }
}
Identity column value is assigned by database when you are inserting record into table. Before you call SaveChanges no queries are executed, nothing is passed to database and back. Context just keeps in-memory collection of entities with appropriate state (state defines which time of query should be executed during changes saving - for new entities, which have Added state, insert query should be generated and executed). So, ID stays with its default value, which is zero for integer. You should not give value manually. After inserting entities into database, context will receive ID value and update entity.
UPDATE: When you are adding Barcode to existing product, then EF is smart enough to update keys and foreign keys of entities:
var product = db.Products.First(); // some product from database
var barcode = new Barcode { BarcodeText = "000" };
// at this point barcode.ID and barcode.ProductID are zeros
product.Barcodes.Add(barcode);
db.SaveChanges(); // execute insert query
// at this point both PK and FK properties will be updated by EF

Searching the Entity Framework domain model utilising Code First

Got a very difficult EntityFramework Code First question. I'll keep this as simple as possible.
Imagine we have n number of classes, lets start with 2 for now
public class Person
{
public string Name { get; set; }
}
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
}
Now then, what I want to do is be able to search the domain model with a single string, i.e. something like DbContext.Search( "Foo" ). The call would search both the person and address tables for a string match and would return a list populated with both Person and Address entities.
Have to say I am not entirely clear how to go about it but I am considering using DataAnnotations to do something like this
public class Person
{
**[Searchable]**
public string Name { get; set; }
}
public class Address
{
**[Searchable]**
public string AddressLine1 { get; set; }
**[Searchable]**
public string AddressLine2 { get; set; }
}
Am I on the right track?
Should I use the Fluent API instead?
Reflection?
Any and all thoughts massively appreciated.
the Find method searches only in the Primary Key column. If we don't make any column explicitly primary key column then find method will throw error. Generally EF convention takes propertyName+id as the primary key in the class. But if you want to search with Name then Make add [Key] to the property. it will become primary key and u will be able to find properties.
dbContext.Addresses.find("Foo");
Create a new object type onto which you'll project 2 types of search results:
public class Result
{
public string MainField { get; set; }
// you may have other properties in here.
}
Then find entities of each type that match your criteria, projecting them onto this type:
var personResults = DbContext.Persons
.Where(p => p.Name == "Foo")
.Select(p => new Result{MainField = p.Name});
// don't forget to map to any other properties you have in Result as well
var addressResults = DbContext.Adresses
.Where(a =>
a.AddressLine1 == "Foo" ||
a.AddressLine2 == "Foo"
).
.Select(a => new Result{MainField = a.AddressLine1 + ", " + a.AddressLine2 });
// again, don't forget to map to any other properties in Result
Then merge the lists:
var allResults = personResults.Union(addressResults).ToList();
...at which point you can sort the list however you like.
"Result" and "MainField", are rather generic; just using them because I am not thoroughly aware of your domain model.

Linq to Entities Complex Dynamic Search

We're using the Entity Framework (MySQL connector) and are creating a central Search facility on our web application.
This link is almost exactly what I need, aside from the fact that he's using pre-defined entities and properties. In our search scenario, we'll have a dynamic number of search terms and fields (ie: user chooses to search on surname, value and city, or provider and advisor).
Is it possible to achieve this kind of functionality with LINQ, so that we can leverage the deferred loading mechanism? I really wanted to avoid generating SQL strings, if possible. I looked at Dynamic LINQ with Expression Trees but couldn't get this to work (or this).
I know you indicated that you wanted to avoid generating SQL strings, but that is often the easiest way. (Much easier than custom Expression Trees). If you are doing this in EF, I recommend you check out Entity Sql which works against your conceptual model but allows for more dynamic querying options than LINQ. LINQ is really suited to compile time query rather than run time queries. You can read up on Entity SQL at http://msdn.microsoft.com/en-us/library/bb387145.aspx.
since last week, we have a similar problem to face, here is an idea i just had for it. thought i share it with you.
interface IPerson
{
DateTime BirthDay { get; set; }
string City { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
}
interface IFilter { }
interface IPersonFilter : IFilter { }
class PersonFilter : IPersonFilter
{
public DateTime? BirthDay { get; set; }
public string City { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
static IQueryable<TSource> ApplyFilter<TSource, TFilter>(IQueryable<TSource> source, TFilter filter) where TFilter : IFilter
{
const BindingFlags bindingFlags = BindingFlags.Public|BindingFlags.Instance|BindingFlags.GetProperty;
var retval = source;
foreach (var filterProperty in filter.GetType().GetProperties(bindingFlags))
{
var elementParameter = Expression.Parameter(source.ElementType, "type");
var elementProperty = Expression.Property(elementParameter, filterProperty.Name);
var value = filterProperty.GetGetMethod().Invoke(filter, null);
if (value != null)
{
var constantValue = Expression.Constant(value, elementProperty.Type);
var expression = Expression.Equal(elementProperty, constantValue);
retval = retval.Where(Expression.Lambda<Func<TSource, bool>>(expression, elementParameter));
}
}
return retval;
}
so the idea is, that you have a filter where the names of the properties of filter match the property names of the object you want to run the filter against. and if the value of the property is not null, i build a expression for it. For the simplicity i do build Expression.Equal expressions only, but i am thinking about extending it.

Using "custom data types" with entity framework

I'd like to know if it is possible to map some database columns to a custom data type (a custom class) instead of the basic data types like string, int, and so on. I'll try to explain it better with a concrete example:
Lets say I have a table where one column contains (text) data in a special format (e.g a number followed by a separator character and then some arbitrary string). E.g. the table looks like this:
Table "MyData":
ID |Title(NVARCHAR) |CustomData (NVARCHAR)
---+----------------+-----------------------
1 |Item1 |1:some text
2 |Item2 |333:another text
(Assume I am not allowed to change the database) In my domain model I'd like to have this table represented by two classes, e.g. something like this:
public class MyData
{
public int ID { get; set; }
public string Title { get; set; }
public CustomData { get; set; }
}
public class CustomData
{
public int ID { get; set; }
public string Text { get; set; }
public string SerializeToString()
{
// returns the string as it is stored in the DB
return string.Format("{0}:{1}", ID, Title);
}
public string DeserializeFromString(string value)
{
// sets properties from the string, e.g. "1:some text"
// ...
}
}
Does entity framework (V4) provide a way to create and use such "custom data types"?
No. Not like that, anyway.
However, you could work around this by:
Write a DB function to do the mapping and then use a defining query in SSDL.
Using one type for EF mapping and another type like you show above, and then projecting.
Add extension properties to your EF type to do this translation. You can't use these in L2E, but it may be convenient in other code.