2016-07-15 3 views
3

que je suis cet excellent exemple: Convert Linq to Sql Expression to Expression Treeconstruction Dynamiquement un arbre d'expression

Dans mon cas, je suis en train de construire un arbre d'expression où le type à filtrer est seulement connu au moment de l'exécution, et est exprimé en un string. Dans l'exemple ci-dessus du type Région est déjà connu et tapé directement:

ParameterExpression pe = Expression.Parameter(typeof(Region), "region"); 

Dans ma demande, je suis en mesure de réécrire ce que:

ParameterExpression pe = Expression.Parameter(Type.GetType("mystring"), "listData"); 

Mon bloc d'achoppement est-ce de la exemple:

MethodCallExpression whereCallExpression = Expression.Call(
      typeof(Queryable), 
      "Where", 
      new Type[] { query.ElementType }, 
      query.Expression, 
      Expression.Lambda<Func<Region, bool>>(e3, new ParameterExpression[] { pe })); 
var results = query.Provider.CreateQuery<Region>(whereCallExpression); 

Dans ces deux lignes Région est directement tapés. Existe-t-il un moyen d'utiliser dynamiquement une chaîne "Region" pour obtenir la même chose?

Répondre

3

Bien sûr, mais vous devrez comprendre les implications. Le nom de type Region est le type d'heure de compilation. Avec lui, vous pouvez générer une requête fortement typée. Cependant, puisque vous n'avez pas le type au moment de la compilation, vous pouvez toujours générer une requête, mais elle ne sera pas fortement typée.

Vous pouvez générer une expression lambda de type heure de compilation inconnue à l'aide des surcharges non génériques. De même avec la méthode CreateQuery().

Voici deux versions de la même requête qui vérifie si une valeur de propriété correspond à une valeur donnée. L'un est générique et l'autre ne l'est pas.

La version générique prend implicitement le type du type de la requête.

public IQueryable<TSource> PropertyEqualsValue<TSource>(IQueryable<TSource> query, 
     string propertyName, object value) 
{ 
    var param = Expression.Parameter(typeof(TSource)); 
    var body = Expression.Equal(
     Expression.Property(param, propertyName), 
     Expression.Constant(value) 
    ); 
    var expr = Expression.Call(
     typeof(Queryable), 
     "Where", 
     new[] { typeof(TSource) }, 
     query.Expression, 
     Expression.Lambda<Func<TSource, bool>>(body, param) 
    ); 
    return query.Provider.CreateQuery<TSource>(expr); 
} 
var query = PropertyEqualsValue(SomeTable, "SomeColumn", "SomeValue"); 

Alors que l'autre type est pris de la condition typeName. Notez que lorsque la requête est créée, nous ne pouvons pas fournir le type, puisque nous ne savons pas quel est le type au moment de la compilation.

public IQueryable PropertyEqualsValue(IQueryable query, 
     Type type, string propertyName, object value) 
{ 
    var param = Expression.Parameter(type); 
    var body = Expression.Equal(
     Expression.Property(param, propertyName), 
     Expression.Constant(value) 
    ); 
    var expr = Expression.Call(
     typeof(Queryable), 
     "Where", 
     new[] { type }, 
     query.Expression, 
     Expression.Lambda(body, param) 
    ); 
    return query.Provider.CreateQuery(expr); 
} 
var type = Type.GetType("Some.Type.Name"); 
var query = PropertyEqualsValue(SomeTable, type, "SomeColumn", "SomeValue"); 
+0

une idée de passer StringComparison.OrdinalIgnoreCase à Expression.Equal appeler? – dodbrian

+1

'Expression.Equal()' correspond à l'utilisation de l'opérateur '=='. Vous ne seriez pas en mesure d'ajouter ce paramètre. Vous devez générer une expression équivalente à 'stringVar.Equals (otherStringVar, StringComparison.OrdinalIgnoreCase)' ou en utilisant le static 'String.Equals (stringVar, otherStringVar, StringComparison.OrdinalIgnoreCase)'. –