I am working on doing a .Find(objects[] keys) method that dynamically creates an lambda function to query a database.
Basically what I want is:
var mykeys = new Guid("37ec1659-b35e-46c9-a7fc-e9802644ca1a");
IQueryable<T> database ;
Func<object[],Expression<Func<T,bool>>> objectFinder = CreateKeyExpression(typeof(T));
var foundObject = database.FirstOrDefault(objectFinder(mykeys));
and
private LambdaExpression CreateKeyExpression(Type C1Type)
{
    ParameterExpression instanceParameter = Expression.Parameter(C1Type);
    ParameterExpression keyParameters = Expression.Parameter(typeof(object[]));
    PropertyInfo[] objectKeys = C1Type.GetKeyProperties().ToArray();
    var expr = Expression.Equal( Expression.TypeAs( Expression.Property(instanceParameter,objectKeys[0]),typeof(object)),
      Expression.ArrayIndex(keyParameters,Expression.Constant(0))); 
    for (int i = 1; i < objectKeys.Length; i++)
    {
        expr = Expression.AndAlso(expr, Expression.Equal(
            Expression.Property(instanceParameter,objectKeys[i]),
            Expression.ArrayIndex(keyParameters,Expression.Constant(i))
            )); 
    }
    var lmp= Expression.Lambda(expr, instanceParameter);
    return Expression.Lambda(lmp, keyParameters);
}
Any ideas of how I can achieve this? The above gives me a Func<object[],Func<T,bool>>, which makes the IQueryable to a IEnumerable, meaning it won't do it on the database end.
You need to use the Expression.Constant method instead of the Expression.ArrayIndex, because you will not be able to pass to your expression array with the key values using the FirstOrDefault method.
private static LambdaExpression CreateKeyExpression(Type C1Type, object[] parameters)
{
    var instanceParameter = Expression.Parameter(C1Type);
    PropertyInfo[] objectKeys = C1Type.GetKeyProperties().ToArray();
    var expr = Expression.Equal(Expression.Property(instanceParameter, objectKeys[0]),
        Expression.Constant(parameters[0], objectKeys[0].PropertyType));
    for (int i = 1; i < objectKeys.Length; i++)
    {
        expr = Expression.AndAlso(expr, Expression.Equal(
            Expression.Property(instanceParameter, objectKeys[i]),
            Expression.Constant(parameters[i], objectKeys[i].PropertyType)));
    }
    return Expression.Lambda(expr, instanceParameter);
}
var parameters = new object[] { Guid.NewGuid(), Guid.NewGuid() };
var lambdaExpression = CreateKeyExpression(typeof(TestClass), parameters);
var testClasses = new List<TestClass>() { new TestClass { Id = (Guid)parameters[0], Id1 = (Guid)parameters[1] } };
var testClass = testClasses.AsQueryable().FirstOrDefault((Expression<Func<TestClass, bool>>)lambdaExpression);
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With