【问题标题】:LINQ to Entities does not recognize the method - Entity Framework and DDDLINQ to Entities 无法识别该方法 - 实体框架和 DDD
【发布时间】:2017-04-10 13:01:17
【问题描述】:

我开始使用 Entity Framework 6 并学习领域驱动设计。

据我了解,根据 DDD 原则,业务逻辑应该驻留在领域层、实体和值对象中。

在我的ApplicationUser 类中,我想要一个方法来说明用户当前是否在聊天中处于活动状态:

public bool IsActiveInChat()
{
    return this.ConnectedToChat &&
       (DateTime.Now - this.LastChatActivity).TotalMinutes < 10;
}

该方法的目的是过滤哪些用户显示在聊天成员列表中。

这是ApplicationUserManager中的查询,也就是Repository

public List<ApplicationUser> GetUsersConnectedToChat()
{
    List<ApplicationUser> users = Users
        .Where(u => u.IsActiveInChat())
        .ToList();

    return users;
}

当我运行这段代码时,我得到了错误:

LINQ to Entities 无法识别方法 'Boolean IsActiveInChat()' 方法,并且该方法不能翻译成 存储表达式。

我可以通过将逻辑转移到Repository 来轻松完成这项工作,但是根据我阅读的有关 DDD 的内容,业务逻辑应该属于实体而不是存储库。

这是同一查询的工作版本(没有ApplicationUser 中的方法):

public List<ApplicationUser> GetUsersConnectedToChat()
{
    List<ApplicationUser> users = Users
        .Where(u => u.ConnectedToChat &&
            DbFunctions.DiffSeconds(DateTime.Now, u.LastChatActivity) < 10)
        .ToList();

    return users;
}

那么,我的问题是:这是 Entity Framework 的一个已知问题吗?

我是不是误会了什么?

有没有办法绕过这个问题并将业务逻辑保留在 User 实体中?

附: - marc_s 提出的问题没有回答我的问题。首先,那里给出的答案建议使用AsEnumerable,它将整个表提取到内存中并且性能不佳。它也没有回答我关于这个问题的领域驱动设计方法是什么的问题,这似乎很常见,而且我在我的项目中会遇到很多。

【问题讨论】:

  • 我编辑了我的问题以解释为什么这不是重复的。
  • 是的,因为它回答了你的第一个问题。其他问题过于宽泛,因为他们首先需要讨论 EF 类模型是域模型的错误假设。这是一个 DAL。
  • 如果有帮助,您可以在调用链的中间应用 AsEnumerable 运算符。之前的所有内容都将被翻译成 SQL 并在 db 服务器上运行。

标签: c# asp.net-mvc entity-framework linq domain-driven-design


【解决方案1】:

这是一个常见的问题。

如果你的过滤逻辑存储在 C# 函数中,那么 sql server 对此一无所知。

你有三个选择。

  1. 从 SQL 中提取所有数据并在本地执行过滤 (正如您所指出的,这可能会导致性能不佳)。

  2. 将过滤逻辑移至 SQL

  3. 尝试编写过滤器 以一种可以传递给 sql 并被 sql 理解的方式实现逻辑。

到 3,我的意思是你可以像这样重写 IsActiveInChat 函数

Expression<Func<ApplicationUser, bool>> IsActiveInChat = r => 
     (r.ConnectedToChat.Value && (DateTime.Now - r.LastChatActivity).TotalMinutes < 10);

或者可能

 Expression<Func<ApplicationUser, bool>> IsActiveInChat = r => 
      (r.ConnectedToChat &&
        DbFunctions.DiffSeconds(DateTime.Now, r.LastChatActivity) < 10)

那么你就可以把这个函数当作

public List<ApplicationUser> GetUsersConnectedToChat()
{
    List<ApplicationUser> users = Users
        .Where(IsActiveInChat)
        .ToList();

    return users;
}

此方法的问题在于您仅限于 SQL 可以处理的函数。例如,如果你尝试,你会得到一个 NotSupportedException

Expression<Func<ApplicationUser, bool>> isJan = r => 
     (r.LastChatActivity.ToSting("MMM")  == "JAN";

【讨论】:

  • 谢谢!一个完整而有用的答案。
猜你喜欢
  • 2021-11-06
相关资源
最近更新 更多