Creating a LINQ Expression where parameter equals object

c#, entity-framework-5, linq

Solution

In addition to what has been mentioned in previous answers. A more specific solution would go as such:

public static Expression CreateExpression<T>(string propertyName, object valueToCompare)
{
    // get the type of entity
    var entityType = typeof(T);
    // get the type of the value object
    var valueType = valueToCompare.GetType();
    var entityProperty = entityType.GetProperty(propertyName);
    var propertyType = entityProperty.PropertyType;


    // Expression: "entity"
    var parameter = Expression.Parameter(entityType, "entity");

    // check if the property type is a value type
    // only value types work 
    if (propertyType.IsValueType || propertyType.Equals(typeof(string)))
    {
        // Expression: entity.Property == value
        return Expression.Equal(
            Expression.Property(parameter, entityProperty),
            Expression.Constant(valueToCompare)
        );
    }
    // if not, then use the key
    else
    {
        // get the key property
        var keyProperty = propertyType.GetProperties().FirstOrDefault(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Length > 0);

        // Expression: entity.Property.Key == value.Key
        return Expression.Equal(
            Expression.Property(
                Expression.Property(parameter, entityProperty),
                keyProperty
            ),
            Expression.Constant(
                keyProperty.GetValue(valueToCompare),
                keyProperty.PropertyType
            )
        );
    }
}

IMPORTANT POINTS :

- Make sure to check for nulls

- Make sure `propertyType` and `valueType` are compatible (either they are the same type or are convertible)

- Several assumptions are made here (e.g. that you do assign a `KeyAttribute`)

- This code is not tested, so it is not exactly copy/paste ready.

Hope that helps.

Problem

Given a primitive value `age` I know how to create an expression like this: ``` //assuming: age is an int or some other primitive type employee => employee.Age == age ``` By doing this: ``` var entityType = typeof(Employee); var propertyName = "Age"; int age = 30; var parameter = Expression.Parameter(entityType, "entity"); var lambda = Expression.Lambda( Expression.Equal( Expression.Property(parameter, propertyName), Expression.Constant(age) ) , parameter); ``` That works fine except in scenarios where the property and constant in question are not primitive types. How would I construct a similar expression if the comparison is between objects? With EF I can just write: ``` Location location = GetCurrentLocation(); employees = DataContext.Employees.Where(e => e.Location == location); ``` That also works, but if I try to create the same expression: ``` var entityType = typeof(Employee); var propertyName = "Location"; var location = GetCurrentLocation(); var parameter = Expression.Parameter(entityType, "entity"); var lambda = Expression.Lambda( Expression.Equal( Expression.Property(parameter, propertyName), Expression.Constant(location) ) , parameter); ``` I get an error that says: `Unable to create a constant value of type 'Location'. Only primitive types or enumeration types are supported in this context.` My suspicion is that `Expression.Constant()` only expects primitive types, so I need to use a different expression factory method. (maype `Expression.Object`? - I know that doesn't exist) Is there a way to create an expression that compares objects? Why is that EF is able to interpret it correctly if its a compiled LINQ statement, but not when it is an expression?

Original source

Related problems