使用 Entity Framework 4 聚合根到子实体导航

Posted

技术标签:

【中文标题】使用 Entity Framework 4 聚合根到子实体导航【英文标题】:Aggregate Root to child entity navigation using Entity Framework 4 【发布时间】:2011-05-09 15:38:28 【问题描述】:

我正在尝试将聚合根模式应用于我的域。我正在使用带有 POCO 实体生成器的 Entity Framework 4。

我有两个实体: 邮寄任务 电子邮件日志 具有一对多的关系。 (MailingTask 有很多 EmailLogs)。 EF4 在 MailingTask 上生成一个导航属性:

public virtual ICollection<EmailLog> EmailLogs

在我的模型中,我永远不想直接访问 EmailLogs,总是通过其父 MailingTask。这是由以下人员强制执行的:

只有一个 MailingTask 存储库,所以我无法直接查询 EmailLogs 表。 仅通过此导航属性获取 EmailLogs。

我有时需要计算 MailingTask 的 EmailLogs 数量。这是通过在导航属性上使用 LINQ 来实现的:

mailingTask.EmailLogs.Count();

但这在应用程序端(不是数据库服务器)执行。 (而且它非常昂贵,因为我有很多用于 MailingTask 的 EmailLogs。)我阅读了一些关于这种行为的帖子,似乎 EF4 导航属性不能用作 IQueryable(在数据库端执行)。当您访问导航属性时,EF4 会在内存中加载所有包含所有列的条目,并在内存中应用 LINQ 表达式。对于 Count() 语句,这很痛苦。

我相信我将不得不更改我的模型以适应这种专门的查询(可能添加具有查询功能的 EmailLogsRepository)。对我来说,似乎 EF4 不能很好地支持聚合根模式。或者我可能遗漏了一些关于聚合根模式以及它应该如何在 EF4 中实现...

有没有人遇到过这种情况并且能够解决这个问题? nHibernate 或其他 ORM 是否能更好地支持这一点?

【问题讨论】:

【参考方案1】:

NHibernate 确实支持 Count() "natively",因为它被映射到 SQL "Select COUNT(*) .." 查询并且不需要实现所有实体 - 这是 EF 会做的相同的查询。

对于实体框架,有一个解决方法可以实现相同的效果,详细信息here。计数查询将如下所示:

int logCount = context.Entry(mailingTask)
                      .Collection(p => p.EmailLogs)
                      .Query()
                      .Count();

这将需要更改此查询的模型,因为您不能直接使用导航属性 /Count() - 这是一个主要缺点,需要在 EF 中尽快修复。

【讨论】:

更改模型以暴露上下文让我很难过。感谢您使用 DbContext 的替代方案,但切换到 NHibernate 可能是我将遵循的路径,即使它会很辛苦。

以上是关于使用 Entity Framework 4 聚合根到子实体导航的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework EF 代码首先使用 ExecuteStoreCommand 执行 sproc 非常慢

非聚合根可以持有另一个非聚合根的引用吗?

一文学会使用Entity Framework Core

一文学会使用Entity Framework Core

Entity Framework Core 性能优化

必看一文学会使用Entity Framework Core