【问题标题】:EF.Property throws "The LINQ expression could not be translated"EF.Property 抛出“无法翻译 LINQ 表达式”
【发布时间】:2022-01-11 21:24:36
【问题描述】:

我正在尝试将软删除改造为使用 EF Core 的 ASP.NET Core 5.0 应用程序。

DbContextOnModelCreating方法中是这样完成的:

builder.Entity<MyEntity>().Property<bool>("IsDeleted");
builder.Entity<MyEntity>().HasQueryFilter(m => EF.Property<bool>(m, "IsDeleted") == false);

这是在docs 中推荐的。我希望避免更改底层数据库实体(如MyEntity)。

异常是在这样的代码上引发的,它曾经完美地工作:

var myEntities= _context.MyEntities.AsNoTracking();
return _mapper.Map<IEnumerable<MyEntity>>(myEntities);

导致(在第二行):

InvalidOperationException: The LINQ expression 'DbSet<MyEntity>()
    .Where(s => EF.Property<bool>(s, __ef_filter___isDeleted_0) == False)' could not be translated.

因为(自然)有很多地方使用 AutoMapper,所以我也不想更改用于返回我的 DTO 的代码。调整 AutoMapper 配置就可以了。

PostgreSQL 被用作底层数据库,如果这有什么不同的话。

我需要如何配置我的查询过滤器,以便现有代码不会引发异常?

// 编辑:

我已经简化了我的示例,确切的代码使用字符串作为属性名称:

private readonly string _isDeleted = "IsDeleted";

builder.Entity<MyEntity>().Property<bool>(_isDeleted);
builder.Entity<MyEntity>().HasQueryFilter(m => EF.Property<bool>(m, _isDeleted) == false);

我可以改变那个变量。

【问题讨论】:

  • 它是否有效_context.MyEntities.AsNoTracking().ToList()
  • @SvyatoslavDanyliv 不,如果我添加这个,则会抛出相同的错误,就在第一行(我添加了.ToList()
  • 所以不是 Automapper 的问题。是否启用了任何扩展?喜欢 LINQKit?
  • 看起来您的示例具有误导性,因为异常消息的__ef_filter___isDeleted_0 部分表明您使用EF.Property&lt;bool&gt;(m, "IsDeleted"),而是使用EF.Property&lt;bool&gt;(m, isDeleted) where @987654334 @ 是一些捕获的变量(类字段)。请确保提供重现问题的确切代码。
  • @IvanStoev 我已经用确切的代码编辑了我的问题

标签: c# linq entity-framework-core automapper


【解决方案1】:

问题是用于指定属性名称的_isDeleted 来自派生contextinstance 字段,并且上下文的实例成员在global query filters。基本上它们被替换为参数,在这种特殊情况下会导致“不可翻译”结构。

解决方案是改用staticconst,例如

private static readonly string _isDeleted = "IsDeleted";

private const string _isDeleted = "IsDeleted";

【讨论】:

    【解决方案2】:

    这里的东西:

    HasQueryFilter(b => EF.Property<string>(b, "_tenantId") == _tenantId);
    

    已完成,因为该字段是私有的。 您仍然需要实体上的字段才能完成这项工作。但是,您可以在您的 automapper 配置中忽略它,这样您就不需要调整您的 dto。

    【讨论】:

      【解决方案3】:

      您不能使用变量作为属性名称。在这种情况下,EF 创建在这种情况下不可翻译的参数。

      解决方案是通过辅助函数动态生成查询过滤器:

      public static Expression<Func<T, bool>> GenerateDeletedFilter<T>(string propName)
      {
          var param = Expression.Parameter(typeof(T), "e");
      
          var filter = Expression.Lambda<Func<T, bool>>(
              Expression.Equal(
                  Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(bool) }, param,
                      Expression.Constant(propName)), Expression.Constant(false)), param);
      
          return filter;
      }
      

      及用法:

      private readonly string _isDeleted = "IsDeleted";
      
      builder.Entity<MyEntity>().Property<bool>(_isDeleted);
      builder.Entity<MyEntity>().HasQueryFilter(GenerateDeletedFilter<MyEntity>(_isDeleted));
      

      【讨论】:

        猜你喜欢
        • 2021-12-28
        • 1970-01-01
        • 2022-12-03
        • 1970-01-01
        • 2021-11-27
        • 2022-10-20
        • 2021-02-11
        • 2020-09-29
        相关资源
        最近更新 更多