Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ to Entities does not recognize the method 'Boolean HasFlag(System.Enum)' when creating the expression via System.Linq.Expressions.Expression

We are using System.Linq.Expressions.Expression to build custom expressions which are applied on the .Where() of our IQueryable.

What I want to achieve is, to apply the .HasFlag() method (introduced in EF 6.1) on the property which is then used in the .Where() expression.

I have following code:

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)));

The value of propertyExpression is being displayed as {x.Type} and the hasFlagMethod is being shown as {Boolean HasFlag(System.Enum)} which both look fine to me.

The value of hasFlagExpression is {x.Type.HasFlag(Convert(Foo))} which also looks completely fine to me except the Convert(Foo) part but doing this was necessary otherwhise I would get another Exception that it is complaining that the parameter cannot be applied to this method as it is not System.Enum.

And at the time we enumerate the IQueryable with this .Where() we get following exception:

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

Calling it directly on the IQueryable works though (we are also using EF 6.1 which added support for Enum.HasFlag()) as in

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

But calling it like this is not an option as it needs to be generic for all our entities. (We put those .Where() conditions together according to the filtered columns in our Datatables)

like image 905
Stefan Schmid Avatar asked Sep 27 '17 14:09

Stefan Schmid


1 Answers

There is a small not easily visible difference between the MethodInfo of the HasFlag method in your code and the one generated by the compiler. The ReflectedType property in the former case is typeof(YourEnum) while in the later - typeof(Enum). The DeclaringType property in both cases is one and the same - typeof(Enum), hence the debug display, but that's enough to break the EF query translator.

To fix the issue, simply change

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

to

var hasFlagMethod = typeof(Enum).GetMethod(nameof(Enum.HasFlag));
like image 68
Ivan Stoev Avatar answered Nov 17 '22 14:11

Ivan Stoev