Entity Framework 4 Abstract Model - How to Programatically Eager-Load Navigational Properties?

∥☆過路亽.° 提交于 2019-12-22 08:24:17

问题


I have an EF4 Model that is built with abstract entities/classes:

Notice how State entity has a navigational property called Country.

Note: I have lazy-loading disabled, so i must eager-load on demand.

Now, if i have the following method:

public Location FindSingle(int id)
{
   return _repository.Find().WithId(id).SingleOrDefault();
}

This does not return any associations by default. But how can i dynamically eager-load the associations when i explicitly want to?

I cannot do this:

return _repository.Find().WithId(id).Include("Country").SingleOrDefault();

As i am working with an abstract class called Location, which does not have a navigational property called "Country". I do not know what the derived type is until i actually execute the query with .SingleOrDefault.

So, here's what i've had to do:

public Location FindSingle(int id, bool includeAssociations = false)
{
    var location = _repository.Find().WithId(id).SingleOrDefault();
    return includeAssociations
                       ? LoadAssociation(location)
                       : location;
}

private Location LoadAssociation(Location location)
{
   // test derived-type, e.g:
   var state = location as State;

   if (state != null) 
      return _repository.Find().OfType<State>().Include("Country").WithId(id).SingleOrDefault();
}

Essentially, i'm doing 2 identical calls. Does it work? Yes. Is it pretty? No, and it's not really "eager-loading".

I know this is not the correct solution, can you guys think of the proper one? (and yes i know i can use stored procedures, but i really want to go through my repository/model here, so the entities are correctly attached to the graph, ready for editing).

Even though .Include causes a Left Outer Join, the problem is i'm working off the "Locations" entity set. I need to .Include on the "State", but "States" belong to the "Locations" entity set (derived classes belong to their parent's entity set).

So i guess my question is actually pretty generic - how do we do a .Include on a child of an abstract entity, when we don't know what the child is beforehand?

Remember, i cannot use .OfType<T>() first (and then the .Include on the derived type), as i don't know what T is (and neither does the calling code), hence generics cannot be utilized here.


回答1:


The real issue here is that you are holding an Id but you don't know what it represents: it could be for a Country or for a State. At some time you presumably did know what it was, but you didn't maintain that information.

After loading a Location from the repository, how do you know which type to cast it to in order to access the relevant relationship property on it? Presumably you have to use as or is with cast and then you can access these properties. Again that kinda smells bad.

The best option here would be to maintain both the Type and the Id of a Location object so you can reload it using the appropriate repository method.

Another option would be to instead move the relationship up to the Location class so that every Location object has a .Parent Location and a .Children Locations collection. Now you can include them in your Include and when you find you have a State you know to look at .Parent and when you have a Country you know to look at .Children. Use null for no parent and an empty collection for no children. Now when you add continents or cities to your Location class you'll be in great shape to use the same model.

A final option which you can sometimes use in situations like this is to Union two queries after converting them to the common base type, e.g. something like:-

context.Locations.OfType<Country>().Include("States").Cast<Location>().Union(context.Locations.OfType<State>().Include("Countries).Cast<Location>());


来源:https://stackoverflow.com/questions/4011211/entity-framework-4-abstract-model-how-to-programatically-eager-load-navigation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!