views:

283

answers:

2

Hello everyone,

I've been wondering about this one for a while now, so I thought it would be worth using my first Stack Overflow post to ask about it.

Imagine I have a discussion with an associated list of messages:

DiscussionCategory discussionCategory = _repository.GetDiscussionCategory(id);

discussionCategory.Discussions is a list of Discussion entities which is not currently loaded.

What I want is to be able to iterate through the discussions in a discussionCategory and say how many messages are in each discussion without fetching the message data.

When I have tried this before I have had to load the Discussions and the Messages so that I could do something like this:

discussionCategory.Discussions.Attach(Model.Discussions.CreateSourceQuery().Include("Messages").AsEnumerable());

foreach(Discussion discussion in discussionCategory.Discussions)
{

int messageCount = discussion.Messages.Count;

Console.WriteLine(messageCount);

}

This seems rather inefficient to me as I am fetching potentially hundreds of message bodies from the database and holding them in memory when all I wish to do is count their number for presentational purposes.

I have seen some questions which touch on this subject but they did not seem to address it directly.

Thanks in advance for any thoughts you may have on this subject.

Update - Some more code as requested:

public ActionResult Details(int id)
    {  
        Project project = _repository.GetProject(id);
        return View(project);
    }

Then in the view (just to test it out):

Model.Discussions.Load();
var items = from d in Model.Discussions select new { Id = d.Id, Name = d.Name, MessageCount = d.Messages.Count() };

foreach (var item in items) {
//etc

I hope that makes my problem a bit clearer. Let me know if you need any more code details.

+1  A: 

I don't have a direct answer but can only point you to the following comparison between NHibernate and EF 4.0 which seems to suggest that even in EF 4.0 there is no out of the box support for getting counts of a related entity collection without retrieving the collection.

http://ayende.com/Blog/archive/2010/01/05/nhibernate-vs.-entity-framework-4.0.aspx

I've upvoted and starred your question. Hopefully someone will chime in with a workable solution.

Brian Hasden
That's wrong for every version of the EF. See my answer.
Craig Stuntz
That's fine. Like I said, I don't have a direct answer to his question but there is a lot of stuff out on the web saying that counts are either hard or impossible. I don't tend to believe someone when they say something is impossible but I wanted to present it to the asker and kick off the discussion.
Brian Hasden
+2  A: 

Easy; just project onto a POCO (or anonymous) type:

var q = from d in Model.Discussions
        select new DiscussionPresentation
        {
            Subject = d.Subject,
            MessageCount = d.Messages.Count(),
        };

When you look at the generated SQL, you'll see that the Count() is done by the DB server.

Note that this works in both EF 1 and EF 4.

Craig Stuntz
Hi there, thanks for the answer. Unfortunately I have tried this before and found that the count property of the anonymous type returned zero for all discussions. I gave this method another try after seeing your answer, but with the same result. Perhaps I am misunderstanding something about the framework as far as keeping the entities 'connected' to the data store is concered. Can anyone else confirm that the above method should work?
Oligarchia
Show your code; you're doing something wrong. We use this feature *extensively* in our shipping applications. I suspect you're trying to do this on an EF association property (like in your question) instead of in an L2E query (like in my answer). Those are completely different; the former is LINQ to Objects; the latter is LINQ to Entities.
Craig Stuntz
The code I used was identical in form to that you provided. Perhaps there is something further up the chain going wrong. I'll see if I can edit my original post to provide additional code if you think that will help. Thanks again for your assistance. I am taking a look at the blog post you linked to right now.
Oligarchia
After reading the blog post you provided it seems that my problem may lie in understanding how to use a repository to supply the same functionality you demonstrate by using the context directly.
Oligarchia
That would explain it. Note that as long as your repository is returning `IQueryable<>` then you can do this kind of projection even outside of the repository, even if it's `IQueryable<SomePoco>` instead of `IQueryable<SomeEntity>`. As long as you stay in the `IQueryable` domain, the EF will always take the `Count()` back to SQL.
Craig Stuntz
Thanks for the tip, I'll go and give it a try.
Oligarchia