LINQ to Entities在通过System.Linq.Expressions.Expression创建表达式时无法识别方法'Boolean HasFlag(System.Enum)'。

7
我们正在使用System.Linq.Expressions.Expression来构建自定义表达式,这些表达式被应用于IQueryable.Where()中。
我想要实现的是,在属性上应用.HasFlag()方法(在EF 6.1中引入),然后将其用于.Where()表达式中。
我有以下代码:
var memberExpression = propertyExpression as MemberExpression;
var targetType = memberExpression?.Type ?? typeof(decimal?);
var value = Enum.Parse(type, searchValue);
var hasFlagMethod = targetType.GetMethod(nameof(Enum.HasFlag));
var hasFlagExpression = Expression.Call(propertyExpression, hasFlagMethod, Expression.Convert(Expression.Constant(value), typeof(Enum)));
propertyExpression的值显示为{x.Type},而hasFlagMethod被显示为{Boolean HasFlag(System.Enum)},两者看起来都很不错。

hasFlagExpression的值为{x.Type.HasFlag(Convert(Foo))},这也看起来完全没问题,除了Convert(Foo)这一部分,但这样做是必要的,否则我将得到另一个异常,即指定的参数类型不能应用于此方法,因为它不是System.Enum

当我们使用.Where()枚举IQueryable时,会出现以下异常:

NotSupportedException: LINQ to Entities does not recognize the method
'Boolean HasFlag(System.Enum)' method, and this method cannot
be translated into a store expression.

直接在 IQueryable 上调用它是有效的(我们也使用 EF 6.1,它添加了对 Enum.HasFlag() 的支持),如下所示:

Entities.Where(x => x.Type.HasFlag(BarEnum.Foo));

但是这样调用并不可行,因为它需要对所有实体都通用。 (我们根据 Datatables 中筛选的列将这些 .Where() 条件组合在一起)
1个回答

6
你的代码中 HasFlag 方法的 MethodInfo 和编译器生成的方法之间存在一个不易察觉的小差异。前者的 ReflectedType 属性为 typeof(YourEnum),而后者为 typeof(Enum)。两种情况下的 DeclaringType 属性都是相同的 - typeof(Enum),因此调试显示正常,但这足以破坏 EF 查询转换器。

要解决这个问题,只需更改:

var hasFlagMethod = targetType.GetMethod(nameof(Enum.HasFlag));

var hasFlagMethod = typeof(Enum).GetMethod(nameof(Enum.HasFlag));

哇,这个我没想到,我以为它应该可以工作,因为我的属性也是一个枚举。谢谢你的回答,我明天会立即在工作中尝试并回复是否成功! :-) - Stefan Schmid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接