I'm trying to 开发者_JS百科apply the Aggregate Root pattern to my domain. I'm using Entity Framework 4 with POCO Entity Generator.
I have two entities: MailingTask EmailLog With a one-to-many relationship. (MailingTask has many EmailLogs). EF4 generates a navigation property on MailingTask:
public virtual ICollection<EmailLog> EmailLogs
Within my model I never want to access EmailLogs directly, always through its parent MailingTask. This is enforced by:
- Having only a MailingTask Repository, so I cannot query the EmailLogs table directly.
- Getting EmailLogs through this navigation property only.
I sometimes need to count the number of EmailLogs for a MailingTask. This is achieved by using LINQ on the navigation property:
mailingTask.EmailLogs.Count();
But this executes on the application-side (not database server). (And it is very expensive since I have a lot of EmailLogs for a MailingTask.) I read a few posts about this behavior and it seems to be that EF4 navigation properties cannot be used as IQueryable (executed on database-side). When you access a navigation property, EF4 loads ALL entries with ALL columns in memory and applies the LINQ expression in memory. For a Count() statement, this hurts a lot.
I believe I will have to change my model to accommodate this specialized querying (possibly adding an EmailLogsRepository with querying abilities). For me, it seems like EF4 does not support the Aggregate Root pattern very nicely. Or maybe I'm missing something about the Aggregate Root pattern and how it should be implemented with regards to EF4...
Did anyone encounter this situation and was able to solve this? Does nHibernate or another ORM support this better?
NHibernate does suppport Count()
"natively", as in it gets mapped to a SQL "Select COUNT(*) .." query and doesn't require for all entities to be materialized - which is what EF would do with the same query.
For Entity Framework there is a workaround to achieve the same, which is detailed here. The query for the count would look something like this then:
int logCount = context.Entry(mailingTask)
.Collection(p => p.EmailLogs)
.Query()
.Count();
This would require changing the model though for this one query, since you cannot work with the navigation property / Count()
directly - which is a major drawback and something that needs to be fixed asap in EF.
精彩评论