0

Recently, we turned Lazy loading and proxy generation off for Entity Framework. Before this, after we committed new changes to EF, we would receive the entire object graph back. What I am doing now is, after the commit I am calling a FindById method on the repository to get the new object back (i am including navigation properties to be placed back onto the newley created object). My question is, is this a standard practice after a create or should the client be responsible for calling the service a second time to get the newly created object?

Save method on service:

public SomeObject Create(SomeObject someObject)
{
     _repository.Add(someObject);
     _repository.UnitOfwork.Commit()

     //this did not exist when lazy loading and proxy generation were enabled.
     var newObject = _repository.FindById(someObject.Id);
     return newObject;

     //Before we would jsut return the created object because everything was loaded.
     //return someObject

}

I just want to know if this is a Best Practice after an object is created with lazy loading and proxy creation disabled. I am curious to know how other developers are handling this.

DDiVita
  • 4,225
  • 5
  • 63
  • 117
  • I do not understand why you want to load an object which you just have saved and still have at hand. If `FindById` uses the same context the `Commit` was using, `newObject` will just refer to the same object as `someObject` which is still attached to the context. My guess is that your question has something to do with loading navigation properties, but it's not clear to me. Does `FindById` contain `Include`s for all navigation properties which are supposed to replace the former lazy loading? – Slauma Mar 28 '12 at 13:13
  • @Slauma, you are correct about the Includes and navigation properties. I do want to load navigation properties after the commit. – DDiVita Mar 28 '12 at 18:47

1 Answers1

2

Before we would jsut return the created object because everything was loaded.

Somehow I doubt that this is true at all. If you call SaveChanges EF does not execute a query to load the navigation properties, no matter if you use lazy loading or not. For example:

Suppose you have orders with a navigation reference to a customer and in the database is already a customer with Id = 1. Now you create an order (lazy loading is enabled):

var order = context.Orders.Create();
order.CustomerId = 1;
context.Orders.Add(order);
context.SaveChanges();

bool isCustomerLoaded = context.Entry(order).Reference(o => o.Customer).IsLoaded;

isCustomerLoaded will be false - unless the customer 1 is already in the context, but then the property will also be populated without lazy loading ("relationship fixup"). Of course as soon as you access order.Customer it will be loaded due to lazy loading, but that happens afterwards and has nothing to do with SaveChanges.

If your code is a good idea or not, depends on the way the returned object is used and what the consumer expects. Generally the closest replacement of lazy loading without lazy loading is explicit loading because both loading strategies perform single queries to load a navigation property. It would mean of course that you have to introduce additional code at consumer side to load the properties whereas with lazy loading "it just works" when you use a property and the query happens behind the scenes in the overloaded property getters of the proxy object. Explicit loading would look like this:

context.Entry(order).Reference(o => o.Customer).Load();
// or for collections
context.Entry(order).Collection(o => o.OrderItems).Load();

You had to call this at the places where you access a navigation property at the first time.

If you know in advance that the object returned from your Create method will need all navigation properties then you could load them with eager loading the way you proposed. But this is definitely a change in your database access patterns compared to lazy loading: Eager loading will only need a single query to load the whole object graph, but this is a potentially very expensive query with a lot of JOINs in the DB and many data returned. Whereas lazy loading and explicit loading will issue multiple queries, but simpler queries with less data returned. Without considering the model details and doing measurements it is impossible to say what is better.

Slauma
  • 175,098
  • 59
  • 401
  • 420
  • you are correct and I was writing this post kind of hurried, so I apologize for the lack of detail. By virtue of the proxies created by EF, I have access to the related entities. This is why I had access to them after the save changes. The navigation were only loaded when I requested them. I have come up with an infrastructure (which I will share) to include specific entities after a commit or general query. – DDiVita Mar 28 '12 at 21:40
  • I am more curious to know if other users are either including (during a reget) or specifically loading entities after a commit. With the Reference().Load, I wonder if that would be more performant then the utilizing Include() like you stated. – DDiVita Mar 28 '12 at 21:40
  • This is a good article: http://thedatafarm.com/blog/data-access/the-cost-of-eager-loading-in-entity-framework/ – DDiVita Mar 28 '12 at 21:44
  • 1
    @DDiVita: I had indeed certain situations where multiple queries with explicit `Load()` were faster than a single query with `Include`. The most extreme example I know about is this: http://stackoverflow.com/a/7780935/270591 (s. the upvoted comment below the answer). But I would not generally say that the performance of `Include` is worse than explicit loading. It's finally a matter of test on a case by case basis. As rule of thumb perhaps: If there are many navigation *collections* on an entity with potentially *many* elements then: Attention when using `Include`! – Slauma Mar 28 '12 at 23:24
  • the link you provided actually helped me with a totally different query I am working on. Cheers! – DDiVita Mar 28 '12 at 23:30