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

Ste*_*mid 6 c# linq enums entity-framework

我们正在使用System.Linq.Expressions.Expression构建自定义表达式,这些表达式应用于.Where()我们的IQueryable.

我想要实现的是,将该.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)));
Run Code Online (Sandbox Code Playgroud)

显示的值propertyExpression显示为,{x.Type}hasFlagMethod显示为{Boolean HasFlag(System.Enum)}对我来说都很好.

的价值hasFlagExpression就是{x.Type.HasFlag(Convert(Foo))}它看起来也完全没什么问题,除了Convert(Foo)一部分,但这样做是必要的otherwhise我会得到另一个异常,它是抱怨,因为它是不是参数不能应用此方法System.Enum.

在我们枚举的时候IQueryable,.Where()我们得到以下异常:

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

IQueryable尽管直接在作品上调用它(我们也使用了增加支持的EF 6.1 Enum.HasFlag()),如

Entities.Where(x => x.Type.HasFlag(BarEnum.Foo));
Run Code Online (Sandbox Code Playgroud)

但是这样称它不是一种选择,因为它需要对我们所有实体都是通用的.(我们.Where()根据数据表中的过滤列将这些条件放在一起)

Iva*_*oev 6

代码MethodInfo中的HasFlag方法与编译器生成的方法之间存在一个不易察觉的小差异.ReflectedType前一种情况下的财产是typeof(YourEnum)在后来的 - typeof(Enum).DeclaringType两种情况下的属性都是同一个 - typeof(Enum)因此调试显示,但这足以打破EF查询转换器.

要解决此问题,只需更改即可

var hasFlagMethod = targetType.GetMethod(nameof(Enum.HasFlag));
Run Code Online (Sandbox Code Playgroud)

var hasFlagMethod = typeof(Enum).GetMethod(nameof(Enum.HasFlag));
Run Code Online (Sandbox Code Playgroud)