Entity Framework - Include / Reference / Collection

c# entity-framework navigation-properties

Question

I was wondering why there are separate methods for populating navigation properties.

If I work on an entire set, i can call Include on either a property or a collection.

However, if I work on a single entity, there are two separate methods to call depending on whether the item is a collection (Collection) or single reference (Reference).

Is there any way around this - this is making things more complicated than I think is necessary. And could anyone explain why this was decided during designing EF?

EDIT

Looking into it further, the problem goes deeper. What I was trying to do is create a generic way to load collection/navigation properties on a single entity. This can be done easy enough on the whole set using Include. But the method signatures for Reference and Collection are slightly different.

Never mind, will have to scatter these calls around my app.

e.g.

dbSet<T>().Include(e => e.Property).Include(e => e.Collection).Include(e => e.Collection.Property) 

all seem to work.

However the calls for the single entity are different:

context.Entry(entity).Reference(e => e.Property).Load();
context.Entry(entity).Reference(e => e.Property.Select(e => e.SubProperty)).Load();
context.Entry(entity).Collection(e => e.Collection).Load();
1
8
8/6/2013 7:33:52 AM

Accepted Answer

The only purpose of the Include() method is to explicitly eager load related data upon querying.

The Entry() method - on the other hand - is intended to give you specific control over the current state of an Entity attached to the context and not only Load() related data.

That is the reason why you have to explicitly choose between Collection, Reference and Property methods, each one exposes different set of functionality (hence returns different type), for example:

  • Scalar (DbPropertyEntry) contains the IsModified property that denotes whether the value changed from 'x' to 'y' (for example).

  • Reference (DbReferenceEntry) contains the IsLoaded property that denotes whether the data has been loaded from the database already (as opposed to 'Scalar' property entry).

  • Reference Collection (DbCollectionEntry) derives from ICollection (hence IEnumberable as well) which mean that you can iterate over it's data. yet, it cannot contain an IsModified property because it may differ for each item in the collection.

Still, if you're only interested in Load() you can leverage the polymorphic Member() method (that returns DbMemberEntry that is the base class to all of the above classes) and check if the entry is 'Loadable':

var memberEntry = this.Entry(entity).Member("NavigationProperty");

if (memberEntry is DbCollectionEntry collectionMember)
    collectionMember.Load();

if (memberEntry is DbReferenceEntry referenceMember)
    referenceMember.Load();
13
11/26/2019 10:50:19 AM

Popular Answer

You can do it this way:

1.- Load the entity including the collections:

MyClass myObject = dbContext.MyClasses
                    .Include(cls => cls.ObjectCollection)
                    .Single(cls => cls.Pk == entityPk);

2.- Then you must retrieve that object Entry and tell EF to load the required properties in the collection objects:

dbContext.Entry(myObject).Collection("ObjectCollection").Query().Include("ReferenceClass").Load(); 

Further reading:

http://msdn.microsoft.com/en-us/data/jj574232#explicitFilter



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