Because EF Contains queries are very slow when n gets large (see Why is .Contains slow? Most efficient way to get multiple entities by primary key?), we are looking into using raw SQL queries instead, i.e. using context.Database.SqlQuery(sql).
What I love about EF (what I think everybody loves), is that you get a complete graph of entities. For example, if you want all Customers, each with with list of their Orders, you might write something like this:
public IEnumerable<Customer> GetCustomersById(List<int> ids)
{
using (var db = new ShoppingCartEntities())
{
return db.Customers
.Include(c => c.Orders)
.Where(ids.Contains(c => c.CustomerID));
}
}
Of course this is a simplified query. In the real world I'd bring back many more columns, and I'd probably use a .Select to create an anonymous type to get around some serialization issues.
This is great because you get back an IEnumerable of type Customer, each with a property called Orders, which is an IEnumerable of type Order.
Using raw SQL, I might do something like the following:
public IEnumerable<Customer> GetCustomersById(List<int> ids)
{
string idsString = string.Join(",", ids);
using (var context = new ShoppingCartEntities())
{
string sql = string.Format(@"
SELECT C.CustomerID, C.Name, C.Address, O.OrderID, O.OrderDate, O.OrderTotal
FROM
Customer C
LEFT JOIN Order O
ON O.CustomerID = C.CustomerId
WHERE C.CustomerID IN ({0})", idsString);
var results = context.Database.SqlQuery<Customer>(sql);
return results;
}
}
So as we all know from (https://entityframework.codeplex.com/workitem/118), Entity Framework will not as present give you back a graph of objects here, but rather a list of Customers, each with a null Orders property. Too bad.
So as far as I see it, my choices at this point are to
- Iterate through the distinct Customer rows, and manually build instances of an Order, then add them to the Customer's Order property, or
- Abandon Entity Framework all together, and do something similar to #1 but with custom business objects.
I'm curious if anyone has first-hand experience dealing with this issue. I searched around and didn't find anything that quite fit the bill.
Note that the reason we need a Contains or IN query in the first place, is that we're getting a list of IDs from another service that we have no control over. Note also that the LEFT JOIN in above SQL is necessary because we want ALL customers, even the ones with no Orders.
Thanks!