Using .Find() & .Include() on the same query

entity-framework

Question

I have the following method automatically generated from the scaffold template with repository:-

public Group Find(int id)
{
    return context.Groups.Find(id);
}

But since the Groups object has two navigation properties which I need , so I wanted to include the .Include, so I replace the .find with .where :-

public Group Find(int id)
{
    return context.Groups.Where(c=>c.GroupID==id)
                         .Include(a => a.UserGroups)
                         .Include(a2 => a2.SecurityRoles)
                         .SingleOrDefault();
}

But my question is how can I apply the .Include with the .find() instead of using .Where()?

1
34
4/24/2017 10:08:33 AM

Accepted Answer

I was just thinking about what find actually does. @lazyberezovsky is right include and find cant be used in conjunction with each other. I think this is quite deliberate and here's why:

The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context. If the entity is not found in the context then a query will be sent to the database to find the entity there. Null is returned if the entity is not found in the context or in the database.

Find is different from using a query in two significant ways:

  • A round-trip to the database will only be made if the entity with the given key is not found in the context.
  • Find will return entities that are in the Added state. That is, Find will return entities that have been added to the context but have not yet been saved to the database.

(from http://msdn.microsoft.com/en-us/data/jj573936.aspx)

Because find is an optimised method it can avoid needing a trip to the server. This is great if you have the entity already tracked, as EF can return it faster.

However if its not just this entity which we are after (eg we want to include some extra data) there is no way of knowing if this data has already been loaded from the server. While EF could probably make this optimisation in conjunction with a join it would be prone to errors as it is making assumptions about the database state.

I imagine that include and find not being able to be used together is a very deliberate decision to ensure data integrity and unnecessary complexity. It is far cleaner and simpler when you are wanting to do a join to always go to the database to perform that join.

40
1/19/2017 8:31:58 PM

Popular Answer

You can't. Find method defined on DbSet<T> type and it returns entity. You can't call Include on entity, so the only possible option is calling Find after Include. You need DbSet<T> type for that, but Include("UserGroups") will return DbQuery<T>, and Include(g => g.UserGroups) will also return DbQuery<T>:

public static IQueryable<T> Include<T>(this IQueryable<T> source, string path) 
    where T: class
{
    RuntimeFailureMethods.Requires(source != null, null, "source != null");
    DbQuery<T> query = source as DbQuery<T>;
    if (query != null)    
        return query.Include(path); // your case
    // ...
}

DbQuery<T> is not a child of DbSet<T> thus method Find is not available. Also keep in mind, that Find first looks for entity in local objects. How would it include some referenced entities, if they don't loaded yet?



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow