1

I have three entities generated by Entity Framework. One is event and this contains navigation properties called frogs and user_bookings. I posted a related question before about performing a sub-query which seems to work but it prevents me overriding lazy loading of a property.

var evts = from evt in context.events.Include("frogs")
           where evt.event_id < 10
           select evt;

This works - the navigation property frogs gets loaded.

However, when I alter the LINQ to this:

var evts = from evt in context.events.Include("frogs")
           where evt.event_id < 10
           select new
           {
               Event = evt,
               HasBooked = evt.user_bookings.Any(x => x.user_id == 1)
           };

I get an error trying to access the frogs because the ObjectContext no longer exists. I tried removing virtual from the class definition for the event class, but this just results in an empty list of frogs, when they are definitely there!

david.s
  • 11,283
  • 6
  • 50
  • 82
Chris K
  • 435
  • 2
  • 10
  • "because the ObjectContext no longer exists" why would that be? Certainly not because of some code posted here. – usr Apr 26 '15 at 20:29
  • Yes, I think I know why the message appears. The data is trying to be fetched when I ask for it for the view that displays it, by which time it's been disposed of. My question is what do I need to do to get it to load the data at query time for the second option? I know I can add `include` in the first example, but that doesn't work for the second one, so my guess is that it's not in the right place when the `select new` part is added. – Chris K Apr 26 '15 at 21:31

1 Answers1

3

This is by design. Include is ignored when the query result is a projection, even when the projection contains an entity that could contain the Included properties.

I don't know why EF implemented it this way. If the projection doesn't contain any entities, but is just some type (anonymous or not), there is no Include target, so ignoring it makes sense. But if the projection does contain an Include target (Event in your case) it seems to me that they could have decided to make that work. But, well, they didn't.

Maybe it's because the rules when Include actually has an effect are less obvious than you might expect. In your case, the shape of the query changes after the Include, so it's ignored.

You could work around this by also querying the frogs:

from evt in context.events.Include("frogs")
where evt.event_id < 10
select new
{
   Event = evt,
   Frogs = evt.frogs,
   HasBooked = evt.user_bookings.Any(x => x.user_id == 1)
};

Now each Event will also have its frogs collection filled (because of relationship fixup). But there are two gotchas. The collections are not marked as loaded, so -

  • if lazy load can occur afterwards, it will occur, making the initial load useless.
  • if lazy loading can't occur any more (because the context is disposed) you will get an exception.

This means that to make this work you have to disable lazy loading.

Community
  • 1
  • 1
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291