Lets say that I have a class called Stock and which has a virtual ICollection Prices, which is a historical set of prices.
If you fetch a stock and after the stock is materialized you query the Prices but apply a filter like mystock.Prices.OrderByDescending(px => px.Date).First(), EF internally loads all the prices and then it applies the filters used, since prices could be a large collection, I would really like to see EF just load the price that matched my where criteria. Basically applying the filtering at the server end rather than client side.
Is it possible to do this?
Thanks
It's possible, but this way only works if you can assume Prices is really an EntityCollection rather than some other class that also happens to implement ICollection. I'm not sure if this is true in all supported EF scenarios. The function to use is EntityCollection's CreateSourceQuery function.
((EntityCollection<Price>)stock.Prices).CreateSourceQuery().OrderByDescending(price => price.Date).First();
If that doesn't work for you, another possibility might be to go back to the context, and query from there:
(from price in context.Prices
where price.StockId == stockId
orderby price.Date descending
select price).First();
Related
This one is driving me nuts!
For simplicity, I'm not gonna put up the entire code that is used for our DDD but simply expose what I've tried and explain what isn't working.
I have a simple database structure:
Products (holds product data)
Orders (holds entered orders)
OrderProducts (ref table between Orders and Product)
I have an Order aggregate root and I want to pull out the product count of one simple Order.
I fetch my Order by id which results in an EF lambda:
var order = _orderRepository.Get(orderId);
Then, I try to pull the count of products in that order using:
var count = order.OrderProducts.Count();
This line chokes up when an order has A LOT a records because, it's fetching all of them. Fine.
So, I'm refining it a bit by adding some filters to the products I want to count from within my order.
A product has a couple of properties which include a type (so, there's a type ID).
So, now I'm trying this:
//This is trimming down my results to about a dozen products)
var count = order.OrderProduct
.Where(op=>op.Product.TypeId == 2)
.Count();
If I use Linqpad to see what kind of SQL is generated, to my surprise, it's still loading ALL the OrderProducts from this order!
How can I force it to apply the filter in the query directly?
It's loading all of them because once you touch the navigation property (i.e. order.OrderProducts) eager loading kicks in and loads all of them (i.e. even the ones that you don't want). Your only option to reduce that would be to query the database itself given the orderID. Maybe something like:
_orderProductRepository.Where(p => p.OrderID == orderId && p.Product.TypeID == 2);
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()
};
One of the few valid complaints I hear about EF4 vis-a-vis NHibernate is that EF4 is poor at handling lazily loaded collections. For example, on a lazily-loaded collection, if I say:
if (MyAccount.Orders.Count() > 0) ;
EF will pull the whole collection down (if it's not already), while NH will be smart enough to issue a select count(*)
NH also has some nice batch fetching to help with the select n + 1 problem. As I understand it, the closest EF4 can come to this is with the Include method.
Has the EF team let slip any indication that this will be fixed in their next iteration? I know they're hard at work on POCO, but this seems like it would be a popular fix.
What you describe is not N+1 problem. The example of N+1 problem is here. N+1 means that you execute N+1 selects instead of one (or two). In your example it would most probably mean:
// Lazy loads all N Orders in single select
foreach(var order in MyAccount.Orders)
{
// Lazy loads all Items for single order => executed N times
foreach(var orderItem in order.Items)
{
...
}
}
This is easily solved by:
// Eager load all Orders and their items in single query
foreach(var order in context.Accounts.Include("Orders.Items").Where(...))
{
...
}
Your example looks valid to me. You have collection which exposes IEnumerable and you execute Count operation on it. Collection is lazy loaded and count is executed in memory. The ability for translation Linq query to SQL is available only on IQueryable with expression trees representing the query. But IQueryable represents query = each access means new execution in DB so for example checking Count in loop will execute a DB query in each iteration.
So it is more about implementation of dynamic proxy.
Counting related entities without loading them will is already possible in Code-first CTP5 (final release will be called EF 4.1) when using DbContext instead of ObjectContext but not by direct interaction with collection. You will have to use something like:
int count = context.Entry(myAccount).Collection(a => a.Orders).Query().Count();
Query method returns prepared IQueryable which is probably what EF runs if you use lazy loading but you can further modify query - here I used Count.
Say I'm modeling a school, so I have 2 Entities: Student and Class. For whatever reason, I want each class roster to have a custom sort order. In a simple relationship, this would mean giving Student a sortOrder attribute and just sorting the list by this number. Issue is, a Student might be order 3 in one Class and order 6 in another. How would I store these orderings in Core Data in a way that I can easily access them and sort my lists properly?
Student Class
classes <<--------->> students
^ ^
| |
unordered ordered
This diagram might help explain what I'm trying to do. The students "roster" I would want to be fetched in a specific order stored somewhere, which could be any ordering. Storing this ordering is what I'm not sure how to do in a way that's the most efficient. Creating a bunch of Order objects and trying to manage the links sounds like a lot of overhead, and it feels like there must be a better way.
If the ordering of students can be described by one or more NSSortDescriptors, you could create a fetched property on the Class entity that fetches the students and applies the sort descriptor. Alternatively, it may be easier (depending on your use case) to apply the sort descriptor(s) to the NSFetchedResultsController that you're using to deal with the class' students collection.
If you can't use an NSSortDescriptor, then you'll need an index attribute (or name of your choice) on the Student entity if there's only one ordering or a collection of Order entities describing the index in each ordering for each Student. You'll be responsible for maintaing these index values. Unfortunately, there's no easy way to do this in Core Data. It's just a lot of work.
Student <<->> StudentClass <<->> Class
StudentClass
----
studentID
order
classID
Then you can select as necessary.
For example, you have a student. Fetch all StudentClass where StudentID is student.studentID. You then have the order, as well as access to the Class.
You'll likely want to add some business logic to make your life easier. Also, if you're not already using it, take a peek at MOGenerator: https://github.com/rentzsch/mogenerator
EDIT: I'd really like to know why this is getting voted down. Comments would be much appreciated.
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.