【问题标题】:EF Core multiple "where" are not translatedEF Core 多个“where”未翻译
【发布时间】:2019-04-02 21:32:27
【问题描述】:

我有一个数据库模型,我想(在运行时)过滤不同的属性。为此,我有每个方法根据属性运行一个“where”子句并返回一个 IQueryable。问题是该子句无法转换为 SQL,因此查询运行时没有“WHERE”语句,返回整个表并且服务器正在执行过滤,这既慢又昂贵。

从日志中,我收到一条消息:

Microsoft.EntityFrameworkCore.Query:警告:LINQ 表达式 'where (new EntityId([ed].EntityId).Id == __entityId_Id_1)' 不能 翻译并在本地进行评估。

我的问题是:我是否在正确的轨道上?如果是的话,我接下来应该看哪里?

主要功能

public static EntityDataDTO GetEntityByKey(this IQueryable<EntityDTO> query, IEntityId entityId, EntityTypeDTO type, string key)
{
    return query
        .HasEntity(entityId)
        .HasType(type)
        .HasKey(key)
        .FirstOrDefault();
}

public static EntityDataDTO GetEntity(this IQueryable<EntityDTO> query, IEntityId entityId, EntityTypeDTO type)
{
    return query
        .HasEntity(entityId)
        .HasType(type)
        .FirstOrDefault();
}

子功能

public static IQueryable<EntityDDTO> HasType(this IQueryable<EntityDTO> query, EntityTypeDTO type)
{
    return query.Where(ed => ed.Type == type);
}

public static IQueryable<EntityDTO> HasEntity(this IQueryable<EntityDTO> query, IEntityId entityId)
{
    return query.Where(ed => ed.EntityId.Id == entityId.Id);
}

实体DTO

public class EntityDTO
    {
        public int Id { get; set; }
        public EntityTypeDTO Type { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }
        public IEntityId EntityId { get; set; }
        public IPartnerId PartnerId { get; set; }
    }

【问题讨论】:

  • 考虑将条件转换为表达式并使用 Where 子句。查看this link
  • 显示你的EntityDTO 班级
  • 为什么要使用 Dtos 作为实体?! DTO = 域传输对象,其中一个实体(与 EF Core/ORM 一起)表示数据库结构。不清楚你想达到什么目标
  • 问题很可能是接口IEntityId - EF(核心)不能很好地处理接口(除了与集合相关的),也不是“值对象”。

标签: c# .net-core entity-framework-core


【解决方案1】:

我认为您发布的任何代码都没有问题。但是,您忽略了发布 HasKey 方法的定义,所以我假设问题确实存在。

在任何情况下,警告都会告诉您有问题的代码到底是什么:new EntityId(ed.EntityId).Id。找到那段代码并更正它。诸如调用新类型之类的东西不能转换为 SQL,因此 EF 必须在内存中运行它。从技术上讲,您可以继续并只允许 EF 执行此操作。但是,这通常表明您将运行低效查询,因此您应该寻找一种更好的方法,而无需在内存中运行该部分查询。

【讨论】:

  • 感谢克里斯的建议!这正是我的问题。它按原样工作,但效率非常低,随着应用程序的增长,这将是一个很大的退步。
【解决方案2】:

您可以使用表达式谓词并为自己构建一个常见的可重用表达式库。这是将其添加到 EntityDTO 的示例,请注意,它返回一个表达式,而不是实际的 IQueryable/IEnumerable:

public partial class EntityDTO
{
  public static Expression<Func<EntityDTO, bool>> HasType(EntityTypeDTO type)
  {
    return ed => ed.Type == type;
  }
  public static Expression<Func<EntityDTO, bool>> HasEntity(IEntityId entityId)
  {
      return ed => ed.EntityId.Id == entityId.Id;
  }
}

【讨论】:

  • 这不是问题。 OP 正在 IQueryable 上使用扩展,这是这种基于表达式的方法的替代方法,但同样可行。
  • @ChrisPratt 同意。考虑到 OP 使用 DTO,两者都是可行的。但是表达方法不是最佳实践吗?特别是如果在数据访问代码中实现?
  • 不一定,尤其是因为这些类似乎命名错误。如果它们被查询,那么它们是实体,而不是 DTO,绝对不是域对象。所以,这只是简单的查询扩展。
猜你喜欢
  • 2021-03-29
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多