2013-08-09 10 views
5

Ich arbeite an einer .Find (objects [] keys) -Methode, die dynamisch eine Lambda-Funktion erstellt, um eine Datenbank abzufragen.Wie kann ich ein Func <object [], Expression <Func<T,bool> >> dynamic?

Im Grunde, was ich will, ist:

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

und

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

Irgendwelche Ideen, wie ich das erreichen kann? Das obige gibt mir eine Func<object[],Func<T,bool>>, die das IQueryable zu einem IEnumerable macht, was bedeutet, dass es auf dem Datenbankende nicht tun wird.

Antwort

2

Sie müssen die Expression.Constant-Methode anstelle der Expression.ArrayIndex verwenden, weil Sie nicht in der Lage sein werden, mit der -Methode an Ihr Expression-Array mit den Schlüsselwerten zu übergeben.

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

interessant, ich löste es ein bisschen anders. Die Angabe von object [] -Parametern in CreateKeyExpression war keine Option. Ich wollte in der Lage sein, den Ausdruck für einen bestimmten C1Type zwischenzuspeichern, weil ich nach einem Func > gefragt habe. Das würde ich für jeden Typ zwischenspeichern und nicht jedes Mal erzeugen, wenn ein neuer Schlüsselsatz verwendet wird. Ich werde meine Lösung auch nur dann posten, wenn andere es wollen. Vielen Dank –

0
private Expression<Func<object[], Expression<Func<C1Source, bool>>>> CreateKeyExpression<C1Source>() 
{ 

    ParameterExpression instanceParameter = Expression.Parameter(typeof(C1Source)); 
    ParameterExpression keyParameters = Expression.Parameter(typeof(object[])); 

    PropertyInfo[] objectKeys = typeof(C1Source).GetKeyProperties().ToArray(); 
    var expr = Expression.Equal(Expression.Property(instanceParameter,objectKeys[0]), 
    Expression.Convert( 
     Expression.ArrayIndex(keyParameters,Expression.Constant(0)), 
     objectKeys[0].PropertyType) 
     ); 

    for (int i = 1; i < objectKeys.Length; i++) 
    { 
     expr = Expression.AndAlso(expr, Expression.Equal(
      Expression.Property(instanceParameter,objectKeys[i]), 
      Expression.Convert(
       Expression.ArrayIndex(keyParameters,Expression.Constant(i)), 
       objectKeys[i].PropertyType) 
       ); 

    } 

    var lmp= Expression.Lambda(expr, instanceParameter); 

    return Expression.Lambda<Func<object[], Expression<Func<C1Source, bool>>>>(lmp, keyParameters); 

} 
Verwandte Themen