views:

283

answers:

3

I think that there's a similar post on here about this but not exactly the same...

I have two entities in my EF model - let's call them Person and Developer, with the latter inheriting from the former.

I also have an association on Developer called Qualifications. This is not visible on the Person entity.

If I'm writing a query against the context, how do I automatically .Include () the Qualifications of the Developer e.g.

from employee in context.Employee .Include ("Qualifications") select employee

doesn't work... EF complains that the relationship does not exist (I assume because it does not exist on Employee - but there's no Developer entity on the context, just Employee).

A: 

I'm not familiar with EF but this looks to me like a standard inheritance problem. If you want to access the unique properties of a child class from a collection of 'parent' objects (where the actual objects may or may not be instances of the child class) then you need to check the object type and cast it to the child where appropriate, then you can access the unique properties.

What would you expect the given statement to return if some or all of the objects were person not developer?

Lazarus
Hi...It should not try to load in the child entities for the base class, because they don't exist. I do the casting to check the child properties etc. - but the whole point of the include is to read it all in in one go (bear in mind that EF doesn't support lazy loading).
Isaac Abraham
I think I'd be inclined to not subclass Person but rather create another class called Developer that has-a Person, that way you can probably retrieve a collection of Person and through association be able to retrieve those that are referenced by a Developer and from that Developer object be able to find those with Qualifications. I.m really not sure it's possible to do what you are trying to do using the class hierarchy you have indicated.
Lazarus
+1  A: 

How about this:

var results = from developer in ctx.Employee.OfType<Developer>()
              select new {developer, Qualifications = developer.Qualifications};

To things are interesting here:

  1. we are excluding employees that aren't Developers
  2. we are then projecting their Qualifications, and as a side effect of that projection, something called fixup with fill each developer.Qualifications too. I.e. this is another way of achieve the same effect as Include().

if you subsequently do this:

var developers = from anon in developers.AsEnumerable()
                 select anon.Developer;

You will get just developers, and they will have their Qualifications loaded too.

See Tip 1 for more info on why this works

Hope this helps

Alex

Alex James
Hi - thanks for the suggestion. I will try that out! It sounds a bit like this isn't an "officially supported" solution though from that link you provided, though.I've gotten around it temporarily by calling Load on the child collection, but this results in a separate SQL call so I'm keen to avoid it if possible.Thanks again.
Isaac Abraham
Although one thing I've just realised - the method that this code lives in should be able to work with both derived and non-derived classes i.e. I should get back a collection of Employees, of which some may be developers (who should then have their Qualifications filled in).
Isaac Abraham
The bit that isn't officially supported on the link was the Sorting of the collection. The actual loading of the collection (all that is used above) is fully supported.
Alex James
A: 

I've come across this problem and experimented a little. Here is what i found worked using LINQ 2 Entity.

Say we have in your example Person <-- Developer ---- Qualification.

If you would like to select a Developer with Qualification included, you would do this.

var dev = (from d in context.Persons.OfType<Developer>.Include("Qualifications")
          where d.ID == id
          select d).FirstOfDefault();

Now lets say we have another association between Person and Address, we can also include Address into the select also using LINQ 2 Entity.

var dev = (from d in context.Persons.Include("Address")
          .OfType<Developer>.Include("Qualifications")
          where d.ID == id
          select d).FirstOfDefault();

Notice how I have included the things I needed before I converted the Type and also included again after the conversion. Both includes should now work together without any problems. I have tested these methods and they both work. I hope they work for you given you have your inheritance setup correctly.

GL.

Tri Q