4

I'm still fairly new to EF (v4.1), so correct me if I'm wrong, but if I have an InverseProperty as follows:

public virtual ICollection<ItemComment> Comments { get; set; }

This will be lazy loaded when the property is accessed. However, if I wish to filter this list - for example, to get only active comments, I could just add another property as follows:

public IEnumerable<ItemComment> ActiveComments {
    get { return Comments.Where(x => x.IsActive); }
}

However, this will load the entire Comments collection first, and then filter right? So not using IQueryable? For performance, ideally I'd like to get the list using IQueryable.

So my question is, can this be done using a property of an entity like this? Or am I going to have to do a where on the ItemComments directly:

var comments = itemCommentRepository.QueryAll()
    .Where(x => x.IsActive && x.ItemId == XX).

This will obviously work... but going forward I wonder if there's a better solution?

Update: It seems the entire result set IS loaded, and any filtering would be done on the whole dataset client-side. Aside from hacks, or changing the entity to pass the context in (yuck!), there doesn't appear to be an in-built way to do so. Have marked @Slauma's response as the answer.

stevehayter
  • 796
  • 1
  • 7
  • 23

1 Answers1

2

this will load the entire Comments collection first, and then filter right?

Yes.

can this be done using a property of an entity

In theory, by injecting the repository or even a context into the entity constructor. But you would have a dependency of your POCO entities on a data access layer. I would not like this solution.

Your proposed solution is a way. You could alternatively use explicit loading:

itemRepository.LoadActiveComments(item);

Implemented like this:

void LoadActiveComments(Item item)
{
    context.Entry(item).Collection(i => i.Comments).Query()
        .Where(c => c.IsActive).Load();
}
Slauma
  • 175,098
  • 59
  • 401
  • 420
  • Curious why you say this will load the entire list of comments first? That hasn't been my experience with navigation properties and lazy loading. – Yuck Nov 16 '12 at 16:17
  • @Yuck It will load all comments *for that item*, regardless of `IsActive`, and then filter on the client. I'm fairly certain that's also what the question asks. You're right that comments for other items won't be loaded. –  Nov 16 '12 at 16:46
  • That was my thinking too - I'm curious whether there's an 'in-built' way of getting it to filter on the server, or whether I have to doing it a different way (using either my alternative, or @Slauma's above) – stevehayter Nov 16 '12 at 16:51
  • @stevehayter: There is a possible solution but it relies on the assumption that the `ICollection` implementation is internally an `EntityCollection` (which is probably true today, but relying on implementation details is a bit dangerous, it might change in the future, breaking your code then). See here: http://stackoverflow.com/a/3411238/270591 and here: http://stackoverflow.com/a/10289147/270591 – Slauma Nov 16 '12 at 16:59
  • @Yuck: My experience is just the opposite :) Also my understanding of how lazy loading works: It is actually the property getter of `item.Comments` that excutes the lazy loading query. The getter is overridden by the dynamic proxy class with code that performs a database query when the property is `virtual`. When the code execution reaches the `Where` method the database query triggered by the collection getter is already done. – Slauma Nov 16 '12 at 17:11
  • @Slauma - that's interesting to know that it is an EntityCollection internally, but you're right - it seems a bit of a hack. And my experience of InverseProperties is the same as yours :). – stevehayter Nov 19 '12 at 09:06