【问题标题】:LINQ throwing TypeAs expression with input of type 1 and check of type 2 is not supported不支持输入类型 1 和检查类型 2 的 LINQ 抛出 TypeAs 表达式
【发布时间】:2013-06-22 05:48:01
【问题描述】:

这一行告诉我不支持带有 User 类型输入和 SoftDeleteEntity 类型检查的“TypeAs”表达式

var test = this.partiallyFiltered.Where(additionalFilter).ToList();

这是里面的东西。 partialFiltered 的类型为 IQueriable<User>。附加过滤器的类型为Expression<Func<User, bool>>,传递的实际表达式(根据调试器)是!((x as SoftDeleteEntity).IsDeleted)。用户继承 SoftDeleteEntity。我认为我没有遗漏任何相关信息,但如果我知道,我会详细说明。我知道一定有一个隐式转换在某处不起作用但我找不到它。

编辑:这里是表达式的声明,所有实体都是IEntity。

public static Expression<Func<TEntity, bool>> DefaultFilter<TEntity>()
        where TEntity : IEntity
{
   if (typeof(SoftDeleteEntity).IsAssignableFrom(typeof(TEntity)))
      return x => !(x as SoftDeleteEntity).IsDeleted;
   else return x => true;
}

【问题讨论】:

  • 您不能在此处使用 as 运算符。尝试改用常规演员表。
  • 现在就尝试一下,但仅供参考,当这段代码工作时,' as ' 就在那里。 编辑:刚刚尝试过,如果我将其更改为 ((SoftDeleteEntity)x),它会显示“无法将 TEntity 转换为 SoftDeleteEntity”。
  • 你必须展示使用完整的代码。你没有给我们太多的继续。
  • 我用相关部分更新了我的问题
  • SoftDeleteEntity 是否实现了IEntity

标签: c# .net linq entity-framework


【解决方案1】:

不幸的是,您将不得不动态地执行此操作。泛型(结合实体框架对类型转换的明显恐惧)不允许您以静态方式编写您想要的代码。所以试试这个:

using System.Linq.Expressions;

public static Expression<Func<TEntity, bool>> DefaultFilter<TEntity>()
    where TEntity : IEntity
{
   if (typeof(SoftDeleteEntity).IsAssignableFrom(typeof(TEntity)))
      return DefaultFilterSoftDelete<TEntity>();
   else return x => true;
}

public static Expression<Func<TEntity, bool>> DefaultFilterSoftDelete<TEntity>()
    where TEntity : IEntity
{
    var parameterExpression = Expression.Parameter(typeof(TEntity));
    var propertyExpression = Expression.Property(parameterExpression,
        "IsDeleted");
    var notExpression = Expression.Not(propertyExpression);
    var lambdaExpression = Expression.Lambda<Func<TEntity, bool>>(notExpression,
        parameterExpression);

    return lambdaExpression;
}

此代码的作用是动态生成您要查找的表达式,而无需表达类型转换;当实体框架遍历该表达式时,它已经被强类型化为特定实体类型(如User)。

编辑:至于代码使用工作的原因,唯一危险的解释是,在代码按预期停止工作之前,您在 @ 中创建的 lambda 表达式987654323@ 函数仅在客户端上运行,并没有被实体框架转换为 SQL。在此过程中,使用过滤器表达式的代码开始将其应用于表示实体集合的IQueryable&lt;T&gt;,而不是内存中的IEnumerable&lt;T&gt;(或类似)集合。您提供的代码可以使用 LINQ to Objects 正常工作,但不能使用实体框架。

【讨论】:

  • 赞成这个,因为最后一句话让我找到了我的解决方案
  • 我试过了,现在我得到“LINQ to Entities 不支持 LINQ 表达式节点类型 'Invoke'。”在我用来获取原始 TypeAs 异常的同一行中
  • 这意味着传递给实体框架的 lambda 表达式之一正在调用无法转换为 SQL 的函数。检查你的表情,看看那是什么。
  • 这是被检查的表达式.Lambda #Lambda1&lt;Func'2[User,Boolean]&gt;(user $var1) { !$var1.IsDeleted } 为什么不能翻译成SQL? IsDeleted 是 BIT 列的名称。
  • 当您将Where 函数应用于您的partiallyFiltered 集合时,您使用的是partiallyFiltered.Where(expression) 还是partiallyFiltered.Where(x =&gt; expression(x)) 语法?因为只有第一个会起作用。您需要按原样传递 lambda 表达式,而不是将其包装在另一个表达式中。
【解决方案2】:

所以我想出了答案,灵感来自亚当的回答。我想出的解决方案如下:

var function = additionalFilter.Compile();
var test = this.partiallyFiltered.Where(x => function(x));

此代码每个实体类型只使用一次,因此在这里编译它似乎不是问题。与其他建议的解决方案相比,这似乎是不太麻烦的解决方案或需要较少重复的解决方案,因此我将在 2 天内接受它,除非其他人提出我的代码曾经工作时间最长的真正原因停止工作。这段代码有效,但它没有解释任何东西,Adam 的解释非常有意义,除了我的静态定义的过滤器之前工作过,我可以从我的历史中看到它的代码从未被修改过。只有我的模型被修改了。

编辑:正如亚当斯所说,编译后的过滤器不会被翻译成 sql(我在想什么),因此只会在本地运行,所以这毕竟不是答案

【讨论】:

  • 我在我的答案中添加了一个编辑,可能是导致行为改变的原因。也许您可以检查您的修订日志以确认这一点。
  • @AdamMaras 考虑到这一点,你有没有像我一样使用编译函数的理由?
  • 是的,使用编译后的表达式将强制过滤子句由您的应用程序运行,而不是传递给实体框架以转换为 SQL。想象一下,如果您有一千条记录,其中 990 条的 IsDeleted 标志设置为 true。使用编译后的表达式,数据库服务器将返回所有 1,000 行,并且您的应用程序必须过滤掉已删除的 990 行。使用未编译的表达式,Entity Framework 可以使用 WHERE 子句向 SQL Server 指示只应返回标志设置为 false 的 10 条记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多