Entity Framework, Computed Entity Field - entity-framework

Is it possible to include a computed field in an EF entity? Example, lets say I have a shop selling products, and the products are grouped into categories.
When the list of categories is displayed for editing to the administrator of the shop I wish to list the number of products in each category as part of the list.
In NHibernate I would use a formula e.g.
<property name="Products" formula="dbo.Category_NumProducts(id)" />
I can't work out if something similar is possible for EF. I know I could make a category view and map this to a second entity but that seems wrong as its almost a complete duplication.
EDIT: If this isn't possible in EF, then what is the best way to accomplish this?

Unfortunately if your Category table doesn't have this as computed column you will not be able to map it without creating second entity - it leads to database view, defining query in EDMX or perhaps Query view in EDMX (but Query view may not work because you require aggregate function to be computed).
Edit:
IMHO the simplest solution (and also the best) is simply creating a ViewModel (some non mapped class) and use projection in Linq query:
var query = from c in context.Categories
where ...
select new CategoryView {
Id = c.Id,
Name = c.Name,
...
Products = c.Products.Count()
};

Related

How to use Entity Framework with a database without relationships defined

I am new to EF so please bear with me. I am using Entity Framework with an existing database in which the relationships are not defined.
Using EF, I am able to produce the model, but obviously the 'navigational properties' are not working. Is there a way I can specify the mapping between the entities?
For example, in my Product entity, I have a field CategoryID_fk (maps to Category entity). But since the relationships are not defined, I cannot load a Category while loading a Product entity.
Can someone guide me in this regard?
I do understand that it would be preferable to refactor our database but I am unable to do that now. Thanks in advance.
This link is very useful.http://www.entityframeworktutorial.net/
I think field names are not suitable conventions.Try to change field name as CategoryId or Category_CategoryId .I think it will work
Yes, you can do a group join. Basically you will retrieve Products and Category in separate queries and take an approach as indicated in this answer.
Something along these lines:
var productCategoryList = products.GroupJoin
(
categories,
p=> p.productId,
c=> c.CategoryId,
(p, c) => new ProductCategory
{
//Create your Product Category model here
}
).AsEnumerable();

adding entries to the "Relational" table in entity model? how do i do that?

so the story is very simple.
I have one table called Products and another Called categories. In addition, i have another table called ProductCategories that hold the relationship of catetories to their corresponding products (i.e, the table has two columns, ProductId, ColumnId).
For some reason, after adding all those table to my entity model, i don't have "Access" to it, hence i can do myentityModel.ProductCategories, so i could relational items between those two tables.
And yes, the ProductCategores table is added as "Association" to the entity model. i don't really understand that.
EDIT:
I do see that as part of creating new "Product" i can pass EntityCollection of "Category". So i do query from my entity model for a list of the matching categories that the user selected (on the webpage). so for example, i get (after query the model), an Objectset of "Category". However, i encountered two issues:
the 'AddObject' accept only EntityCollection, hence i need to re-create a set and then add all the objects from the ObjectSet to the entityCollection, in this process i need to detach it from the previous model and add it to the new collection. if not, i get an exception.
when i do the SaveChanges, i see that i get an exception that it was actually trying to Create new Category rather than adding new ProductCategory. again, am i missing something here?
Thanks.
This sounds like a Many-to-Many relationship. In your entity model, you don't need to declare the join table as a separate entity. Instead, you configure the relationship between the Products and the Categories as a Many-to-Many and add metadata about the join table. In Hibernate, you would have:
#ManyToMany(targetEntity=Categories.class, cascade={CascadeType.ALL}, fetch = FetchType.LAZY)
#JoinTable(name="tb_products_categories",
joinColumns=#JoinColumn(name="category_id"),
inverseJoinColumns=#JoinColumn(name="product_id")
)
#IndexColumn(name="join_id")
public List<Categories> getCategories() {
return categories;
}
When you query, the ORM layer takes care of determining SQL and traversing table joins.

Entity Framework many-to-many question

Please help an EF n00b design his database.
I have several companies that produce several products, so there's a many-to-many relationship between companies and products. I have an intermediate table, Company_Product, that relates them.
Each company/product combination has a unique SKU. For example Acme widgets have SKU 123, but Omega widgets have SKU 456. I added the SKU as a field in the Company_Product intermediate table.
EF generated a model with a 1:* relationship between the company and Company_Product tables, and a 1:* relationship between the product and Company_Product tables. I really want a : relationship between company and product. But, most importantly, there's no way to access the SKU directly from the model.
Do I need to put the SKU in its own table and write a join, or is there a better way?
I just tested this in a new VS2010 project (EFv4) to be sure, and here's what I found:
When your associative table in the middle (Company_Product) has ONLY the 2 foreign keys to the other tables (CompanyID and ProductID), then adding all 3 tables to the designer ends up modeling the many to many relationship. It doesn't even generate a class for the Company_Product table. Each Company has a Products collection, and each Product has a Companies collection.
However, if your associative table (Company_Product) has other fields (such as SKU, it's own Primary Key, or other descriptive fields like dates, descriptions, etc), then the EF modeler will create a separate class, and it does what you've already seen.
Having the class in the middle with 1:* relationships out to Company and Product is not a bad thing, and you can still get the data you want with some easy queries.
// Get all products for Company with ID = 1
var q =
from compProd in context.Company_Product
where compProd.CompanyID == 1
select compProd.Product;
True, it's not as easy to just navigate the relationships of the model, when you already have your entity objects loaded, for instance, but that's what a data layer is for. Encapsulate the queries that get the data you want. If you really want to get rid of that middle Company_Product class, and have the many-to-many directly represented in the class model, then you'll have to strip down the Company_Product table to contain only the 2 foreign keys, and get rid of the SKU.
Actually, I shouldn't say you HAVE to do that...you might be able to do some edits in the designer and set it up this way anyway. I'll give it a try and report back.
UPDATE
Keeping the SKU in the Company_Product table (meaning my EF model had 3 classes, not 2; it created the Company_Payload class, with a 1:* to the other 2 tables), I tried to add an association directly between Company and Product. The steps I followed were:
Right click on the Company class in the designer
Add > Association
Set "End" on the left to be Company (it should be already)
Set "End" on the right to Product
Change both multiplicities to "* (Many)"
The navigation properties should be named "Products" and "Companies"
Hit OK.
Right Click on the association in the model > click "Table Mapping"
Under "Add a table or view" select "Company_Product"
Map Company -> ID (on left) to CompanyID (on right)
Map Product -> ID (on left) to ProductID (on right)
But, it doesn't work. It gives this error:
Error 3025: Problem in mapping fragments starting at line 175:Must specify mapping for all key properties (Company_Product.SKU) of table Company_Product.
So that particular association is invalid, because it uses Company_Product as the table, but doesn't map the SKU field to anything.
Also, while I was researching this, I came across this "Best Practice" tidbit from the book Entity Framework 4.0 Recipies (note that for an association table with extra fields, besides to 2 FKs, they refer to the extra fields as the "payload". In your case, SKU is the payload in Company_Product).
Best Practice
Unfortunately, a project
that starts out with several,
payload-free, many-to-many
relationships often ends up with
several, payload-rich, many-to-many
relationships. Refactoring a model,
especially late in the development
cycle, to accommodate payloads in the
many-to-many relationships can be
tedious. Not only are additional
entities introduced, but the queries
and navigation patterns through the
relationships change as well. Some
developers argue that every
many-to-many relationship should start
off with some payload, typically a
synthetic key, so the inevitable
addition of more payload has
significantly less impact on the
project.
So here's the best practice.
If you have a payload-free,
many-to-many relationship and you
think there is some chance that it may
change over time to include a payload,
start with an extra identity column in
the link table. When you import the
tables into your model, you will get
two one-to-many relationships, which
means the code you write and the model
you have will be ready for any number
of additional payload columns that
come along as the project matures. The
cost of an additional integer identity
column is usually a pretty small price
to pay to keep the model more
flexible.
(From Chapter 2. Entity Data Modeling Fundamentals, 2.4. Modeling a Many-to-Many Relationship with a Payload)
Sounds like good advice. Especially since you already have a payload (SKU).
I would just like to add the following to Samuel's answer:
If you want to directly query from one side of a many-to-many relationship (with payload) to the other, you can use the following code (using the same example):
Company c = context.Companies.First();
IQueryable<Product> products = c.Company_Products.Select(cp => cp.Product);
The products variable would then be all Product records associated with the Company c record. If you would like to include the SKU for each of the products, you could use an anonymous class like so:
var productsWithSKU = c.Company_Products.Select(cp => new {
ProductID = cp.Product.ID,
Name = cp.Product.Name,
Price = cp.Product.Price,
SKU = cp.SKU
});
foreach (var
You can encapsulate the first query in a read-only property for simplicity like so:
public partial class Company
{
public property IQueryable<Product> Products
{
get { return Company_Products.Select(cp => cp.Product); }
}
}
You can't do that with the query that includes the SKU because you can't return anonymous types. You would have to have a definite class, which would typically be done by either adding a non-mapped property to the Product class or creating another class that inherits from Product that would add an SKU property. If you use an inherited class though, you will not be able to make changes to it and have it managed by EF - it would only be useful for display purposes.
Cheers. :)

How do you determine subtype of an entity using Inheritance with Entity Framework 4?

I am just starting to use the Entity Framework 4 for the first time ever. So far I am liking it but I am a bit confused on how to correctly do inheritance.
I am doing a model-first approach, and I have my Person entity with two subtype entities, Employee and Client. EF is correctly using the table per type approach, however I can't seem to figure out how to determine what type of a Person a specific object is.
For example, if I do something like
var people = from p in entities.Person select p;
return people.ToList<Person>();
In my list that I form from this, all I care about is the Id field so i don't want to actually query all the subtype tables (this is a webpage list with links, so all I need is the name and the Id, all in the Persons table).
However, I want to form different lists using this one query, one for each type of person (so one list for Clients and another for Employees).
The issue is if I have a Person entity, I can't see any way to determine if that entity is a Client or an Employee without querying the Client or Employee tables directly. How can I easily determine the subtype of an entity without performing a bunch of additional database queries?
Use .OfType<Client>() in your query to get just the clients. See OfType.
e.g. entities.Person.OfType<Client>() ...
Use is to test if a Person object is a specific sub-class, e.g. if (p is Employee) ...
BTW why isn't it entities.People? Did you not select the pluralization option?

How to sort related entities with eager loading in ADO.NET Entity Framework

Greetings,
Considering the Northwind sample tables Customers, Orders, and OrderDetails I would like to eager load the related entities corresponding to the tables mentioned above and yet I need ot order the child entities on the database before fetching entities.
Basic case:
var someQueryable = from customer in northwindContext.Customers.Include("Orders.OrderDetails")
select customer;
but I also need to sort Orders and OrderDetails on the database side (before fetching those entities into memory) with respect to some random column on those tables. Is it possible without some projection, like it is in T-SQL? It doesn't matter whether the solution uses e-SQL or LINQ to Entities. I searched the web but I wasn't satisfied with the answers I found since they mainly involve projecting data to some anonymous type and then re-query that anonymous type to get the child entities in the order you like. Also using CreateSourceQuery() doesn't seem to be an option for me since I need to get the data as it is on the database side, with eager loading but just by ordering child entities. That is I want to do the "ORDER BY" before executing any query and then fetch the entities in the order I'd like. Thanks in advance for any guidance. As a personal note, please excuse the direct language since I am kinda pissed at Microsoft for releasing the EF in such an immature shape even compared to Linq to SQL (which they seem to be getting away slowly). I hope this EF thingie will get much better and without significant bugs in the release version of .NET FX 4.0.
Actually I have Tip that addresses exactly this issue.
Sorting of related entities is not 'supported', but using the projection approach Craig shows AND relying on something called 'Relationship Fixup' you can get something very similar working:
If you do this:
var projection = from c in ctx.Customers
select new {
Customer = c,
Orders = c.Orders.OrderByDescending(
o => o.OrderDate
)
};
foreach(var anon in projection )
{
anon.Orders //is sorted (because of the projection)
anon.Customer.Orders // is sorted too! because of relationship fixup
}
Which means if you do this:
var customers = projection.AsEnumerable().Select(x => x.Customer);
you will have customers that have sorted orders!
See the tip for more info.
Hope this helps
Alex
You are confusing two different problems. The first is how to materialize entities in the database, the second is how to retrieve an ordered list. The EntityCollection type is not an ordered list. In your example, customer.Orders is an EntityCollection.
On the other hand, if you want to get a list in a particular order, you can certainly do that; it just can't be in a property of type EntityCollection. For example:
from c in northwindContext.Customers
orderby c.SomeField
select new {
Name = c.Name,
Orders = from o in c.Orders
orderby c.SomeField
select new {
SomeField = c.SomeField
}
}
Note that there is no call to Include. Because I am projecting, it is unnecessary.
The Entity Framework may not work in the way you expect, coming from a LINQ to SQL background, but it does work. Be careful about condemning it before you understand it; deciding that it doesn't work will prevent you from learning how it does work.
Thank you both. I understand that I can use projection to achieve what I wanted but I thought there might be an easy way to do it since in T-SQL world it's perfectly possible with a few nested queries (or joins) and order bys. On the other hand seperation of concerns sounds reasonable and we are in the entity domain now so I will use the way you two both recommended though I have to admit this is easier and cleaner to achieve in LINQ to SQL by using AssociateWith.
Kind regards.