Friday, February 01, 2008

In my post about rewriting Brad Abram's MVC + Entity Framework example in VB, I pointed out a better way to query a collection of objects and return their entity references (eg, query products and bring along the category information) without writing a scary query filled with references, checks for nulls, etc.

But there was something bothering me about the query.

I went from this (Brad's)

List<Product> products =TheProducts.Where(c => c.Category.CategoryName == category).ToList();
//prepare the view by explicitly loading the categories  
products.FindAll(p => p.Category == null).ForEach(p => p.CategoryReference.Load()); 

To this

     var _prod = Northwind.Categories.
              Where(c => c.CategoryName == id).
              OrderBy(c => c.CategoryName).
              Select(c => c.Products).
              First().ToList();

Which gives the same effect of ending up with a set of products and being able to drill into product.category.categoryname, etc.

But that query represents something that Entity Framework is not supposed to do, and I asked Danny Simmons about it.

Entity Framework will not perform actions that you did not request. I selected only products in my projection, yet I also got back categories. It was convenient, but it was against the promise of EF. I didn't ask for categories.

In the end, a bug was filed, because indeed, that shouldn't be happening.

However, it's still VERY easy to explicitly tell EF to bring along a collection (eg if I query categories I can say "and give me those products while your at it) or an entity ref (query products and ask for the category) by using Include.

Here's the same query for the MVC view even simpler.

    var _products = Northwind.Products.Include("Category").
        Where(p => p.Category.CategoryID == 1).ToList();

There are other ways to achieve this as well, but for this scenario, this is the most streamlined (as far as I know ;-)).
Friday, February 01, 2008 9:08:15 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [4]  | 
Friday, February 01, 2008 10:00:18 AM (Eastern Standard Time, UTC-05:00)
I also wondered about the query I used to return Orders that also can return Customer info (although I only used the Order info for the particular app I built):

var query = ctxNwind.Customers
.Where(cust => cust.CustomerID == customerIDTextBox.Text)
.Select(c => c.Orders
.Select(o => o))
.FirstOrDefault()
.OrderByDescending(o => o.OrderDate);
orderBindingSource.DataSource = query.ToList();

The above came from an LINQ to Entities Sample Queries example.

I changed the query to a version of your more conventional style;

var query = ctxNwind.Orders.Include("Customers")
.Where(o => o.Customers.CustomerID == customerIDTextBox.Text)
.OrderByDescending(o => o.OrderDate);
orderBindingSource.DataSource = query.ToList();

It gave the same result as the above, but took 65% longer to execute! (Average 105 ms. vs. 63 shown at http://oakleafblog.blogspot.com/2008/01/linq-and-entity-framework-posts-for_29.html). Very strange.

--rj

Friday, February 01, 2008 6:00:06 PM (Eastern Standard Time, UTC-05:00)
Julie,

I spent a bit more time cleaning up the performance timing and found the original query's performance was about 30% (rather than 60%) better on my test machine. The details are at http://oakleafblog.blogspot.com/2008/02/entity-sql-queries-for-retrieving.html
Friday, February 08, 2008 9:45:28 AM (Eastern Standard Time, UTC-05:00)
One question: I've been working with LINQ to SQL. I see the EDM is going to use the same context and LINQ statements?

Is that a true statement?

One of the problems I have with LINQ to SQL is the way 'attach' is implemented does EDM use the same or does it have a different way to handle disconnected data?

Thanks for the post
Friday, February 08, 2008 10:20:55 AM (Eastern Standard Time, UTC-05:00)
Hi Steve. They both have contexts which work in a relatively similar way, though LINQ to SQL's is a System.Data.Linq.DataContext and EF's is System.Data.Objects.ObjectContext.

The loss of change tracking is a huge issue with LINQ to SQL and Entity Framework too. I have written a LOT of posts on this - with workarounds. Danny Simmons (blogs.msdn.com/dsimmons) has as well and even has been experimenting with an Entity State bag to possibly solve the problem. The context (datacontext and objectcontext) keep track of all of the state for the entities vs. what many of us are used to with datasets or other ORMs where the state is self-contained by the object. There are a lot of reasons for this, but the big downside is overcoming the problem.

One thing however, is that there are definitely more helper tools for attaching (especially if you have an object graph that is more than one object deep) in Entity Framework because they are still finishing up V1 whereas LINQ to SQL is what it is until we get some type of update. I wonder if there will be anything in SP1?
Julia Lerman
All comments require the approval of the site owner before being displayed.
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview