DDD, EF, Aggregations
I'm experimenting with DDD and EF 4.1 Code First. I have an Aggregate Root BlogEntry which looks simlar to this:
public class BlogEntry
{
public long Id { get; set; }
public string Title { get; set;}
public string Content { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<BlogEntryComment> Comments { get; set; }
}
Now, I want to display the title of the latest 10 Blog Entries and the amount of comments to these Blog Entries in a web portal.
Currently this is implemented similar to this:
foreach(BlogEntry be in blogEntryRepository.GetLatestBlogEntries())
{
string title = be.Title;
int amountOfComments = be.Comments.Count();
// display title, amountOfComments, .开发者_Go百科..
}
Unfortunatelly what Entity Framework does here is to execute one query to get the BlogEntry objects and after that it executes one query for each BlogEntry to retrieve the number of comments.
-> EF generated SQL is similar to this:
select top 10 * from BlogEntry order by Created desc
and then 10 times:
select count(*) from BlogEntryComment where BlogEntry = @blogEntryId
How can I prevent this behaviour in a way without eager loading all Comments but still not shooting a query for each BlogEntry against the database - but without conflicting any DDD rules?
(what I'd like EF to fire against the database is something like this:)
select top 10
be.*,
(select count(*) from BlogEntryComment c where c.BlogEntryId = be.Id) as AmountOfComments
from BlogEntry be order by be.Created DESC
Thanks.
I would choose simpler and most certainly more efficient way - just add the NumberOfComments as property on BlogEntry, increment it with every comment and persist it. Just base on the fact that aggregate has a responsibility of keeping the data consistent. Taking into account the number of requests to just display the data versus the number of actual updates I see no reason to count this number every time someone wants to see it.
you can do like this , but it will create anonymous type,
var p= from a in db.BlogEntries
select new {a, a.Comments.Count};
var k = p.ToList();
Edit.. you can do like this,
Disable lazy loading, Add comment count property to blogEntry domain class
public class BlogEntry
{
public int commentCount{
get
{
if(this.comments==null){
return this._commentCount
}else{
return this.Comments.count;
}
}
set{
this._commentCount=value;
}
}
//other properties...
}
Add new method to your repository to get all with comment count,
var p= from a in db.BlogEntries
select new BlogEntry{Id=a.Id,CommentCount= a.Comments.Count , ect..};
var k = p.ToList();
精彩评论