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?