How do I convert an Enum to an Int for use in an Expression.Equals operation?

c# expression-trees linq-to-sql

Question

I am trying to dynamically build an expression tree in C#, which is compiled and used as the predicate for LINQ-to-SQL Where() call. The problem is that I am trying to compare an Enum (with int as its underlying type) directly against an Int, but this is failing with the error "The member MyEnumType has no supported translation to SQL".

Code:

ParameterExpression param = Expression.Parameter(typeof(MyClass), "obj"); //input parameter - this exposes a property of the Enum type
MemberExpression enumMember = Expression.Property(param, "MyEnumProperty"); //used to get the Enum typed property from the parameter

//MISSING STEP TO CAST THE ENUM OF THE MEMBER EXPRESSION TO AN INT?

BinaryExpression binaryExpr = Expression.Equal(enumMember, Expression.Constant(1));
LambdaExpression<Func<MyClass, bool>> whereClause = Expression.Lambda(binaryExpr, param);

//when whereClause is used to filter LINQ-to-SQL results, the error is thrown

I'm fairly new to expression trees and I can't figure this out. I have tried using

Expression.Convert(enumMember, typeof(int))

as the first part of the BinaryExpression but this doesn't fix it.

Any help is much appreciated.

Expert Answer

Simply, you shouldn't have to, as long as you've told LINQ-to-SQL about the enum (rather than mapping it as an int and having a separate property in C# that does the translation). For example, the following works fine:

var param = Expression.Parameter(typeof(DomainObject));
var body = Expression.Equal(Expression.Property(param, "SomeProperty"),
                         Expression.Constant(YourEnumType.SomeEnum));
var predicate = Expression.Lambda<Func<DomainObject, bool>>(body, param);
var count = db.Table.Where(predicate).Count();

The main point is that my SomeProperty property is mapped in the dbml to the enum. Simply overtype the type name with the enum type (including namespace).

Likewise, you shouldn't be giving it a 1, but rather the typed enum; for example:

Expression.Constant(Enum.ToObject(typeof(YourEnumType), 1))

(if all you know is 1)


Popular Answer

Thanks To Marc Gravell. (Expression Guru !) See Correct answer. I made a change to an Expression Routine to cater for this scenario. Normal properties or Enums. Incase someone finds this helpful

public static Expression<Func<TPoco, bool>> GetEqualsPredicate<TPoco>(string propertyName,
                                                                          object value)
                                                                          Type fieldType )
    {     

        var parameterExp = Expression.Parameter(typeof(TPoco), @"t");   //(tpoco t)
        var propertyExp = Expression.Property(parameterExp, propertyName);// (tpoco t) => t.Propertyname

        var someValue = fieldType.IsEnum // get and eXpressionConstant.  Careful Enums must be reduced
                     ? Expression.Constant(Enum.ToObject(fieldType, value)) // Marc Gravell fix
                     : Expression.Constant(value, fieldType);

        var equalsExp = Expression.Equal(propertyExp,  someValue); // yes this could 1 unreadble state if embedding someValue determination

        return Expression.Lambda<Func<TPoco, bool>>(equalsExp, parameterExp); 
    }



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why