开发者

Eager loading property of derived class using Include

开发者 https://www.devze.com 2023-03-10 18:25 出处:网络
I have classes like: Person { Name Address } Employee : Person { Co开发者_如何学运维mpensation - object

I have classes like:

Person
{
   Name
   Address
}

Employee : Person
{
   Co开发者_如何学运维mpensation - object
}

Visitor : Person
{

}

If I write linq:

var persons = Context.Persons
                .Include("Compensation");

I get error:

A specified Include path is not valid. The EntityType 'Person' does not declare a navigation property with the name 'Compensation'.

It works ok if I do:

var persons = Context.Persons
                .OfType<Employee>()
                .Include("Compensation");

But I would like to get Employees and visitors in the same query.

Looks like there is a request for this feature on EF4 UserVoice: http://data.uservoice.com/forums/72025-ado-net-entity-framework-ef-feature-suggestions/suggestions/1249289-include-property-of-derived-classes?ref=title

but it does not look like it will get done any time soon.

What is a good workaround for this issue?


You can try it this way:

var persons = Context.Persons
                     .OfType<Employee>()
                     .Include("Compensation")
                     .Concat<Person>(Context.Persons.OfType<Visitor>());


Here's a nice example of how to load Persons and include Compensation for Employees

Replace Reference() by Collection() for a collection property.

IQueryable<Person> GetPersons()
{
    var persons = Context.Persons;
    foreach(var entry in persons.OfType<Employee>())
        Context.Entry(entry).Reference(e => e.Compensation).Load();
    return persons;
}

Not sure either if it's efficient, but it works, and the intention is clearer than with joins.

Based on this SO answer


var employees = context.Persons.OfType<Employee>().Include(x => x.Compensation).ToArray();

var nonEmployees = context.Persons.Except(context.Persons.OfType<Employee>()).ToArray();

var people = employees.Concat(nonEmployees);


This horrible thing works:

var persons = context.Persons
                .Concat(context.Employees
                    .Where(e => e.Compensation.Amount >= 0))
                .Concat(context.Visitors
                    .Where(v => v.SomeProperty == "AlwaysTrue"));

I'm not sure why, but when you filter on an object property, the property's object is eagerly loaded. If you don't want to filter that property, then use a condition that will always be true.

Disclaimer: I have no idea how efficient the resulting query is. I checked the sql generated when I tested this in a slightly more complicated scenario and it was very very large.

0

精彩评论

暂无评论...
验证码 换一张
取 消