web-dev-qa-db-fra.com

Générer dynamiquement des requêtes LINQ

Nous avons un objet

public class SomeObject
{
   public Name {get;set;}
   public City {get;set;}
   public State {get;set}
   //various other parameters.  Let's say there's ~20
}

Est-il possible de créer dynamiquement de nouvelles requêtes LINQ sans recompilation du code source? Au lieu de cela, les paramètres de requête proviennent d'une structure XML qui est stockée et mise à jour dans la base de données.

var result = from i in someObj
             where 
             //XML requests Name = 'Bob'...so append this where clause
             name = 'Bob'

Cela peut-il être fait?

34
P.Brian.Mackey

Voici une solution avec des arbres d'expression:

var param = Expression.Parameter(typeof(SomeObject), "p");
var exp = Expression.Lambda<Func<SomeObject, bool>>(
    Expression.Equal(
        Expression.Property(param, "Name"),
        Expression.Constant("Bob")
    ),
    param
);
var query = someObj.Where(exp);

Je sais que c'est beaucoup plus complexe, mais cela peut être utile à certains moments.

117
Balazs Tihanyi

Vous voudrez certainement jeter un œil à Dynamic Linq qui vous permettra de définir les conditions de la requête sous forme de texte.

Quant à l'ajout dynamique de conditions, vous pouvez ajouter des conditions à une requête en utilisant une syntaxe similaire à;

if(CategoryIsImportant)
    myQuery = myQuery.Where("CategoryId=2");

tout cela que vous pouvez (assez facilement) encoder dans un format XML de votre choix.

27
Joachim Isaksson

C'est difficile pour moi de dire en fonction de votre question, mais dans certains cas, vous n'avez pas besoin de Linq dynamique et pouvez simplement le faire ...

var result = from o in someObj 
             where (Name == null || o.Name == Name)
             && (City == null || o.City == City)
             && (State == null || o.State == State)
             select o;

Cela empêchera essentiellement le filtrage des données lorsque le paramètre en question est nul. Et il fonctionne toujours bien grâce au comportement de court-circuit en C #.

26
Steve Wortham

Je pense que vous devrez creuser dans Expression Trees . Je n'ai pas creusé très loin, donc je ne peux pas créer d'échantillon pour vous, mais je sais que vous pouvez utiliser des arbres d'expression pour créer dynamiquement vos requêtes, puis appeler .Compile (dans le code) pour le lancer.

En fait, voici un meilleur lien Création de requêtes dynamiques avec des arbres d'expression . Il devrait vous donner exactement ce que vous voulez et est assez succinct pour ce que c'est. Cela devrait vous servir d'exemple :)

9
Justin Pihony

Peut-être que Dynamic Linq peut vous aider: Dynamic linq part 1: Utilisation de la bibliothèque de requêtes dynamiques linq

query = query.Where("Id = 123 And Age > 18");

Ou vous pouvez manipuler votre requête Linq directement:

query = query.Where(x=>x.Id == 5);
8
Antineutrino

Je suppose que vous souhaitez introduire des filtres facultatifs, en fonction du contenu de votre XML. Pour continuer sur l'exemple de StriplingWarrior:

var name = GetNameFromXml();
var city = GetCityFromXml();
var state = GetStateFromXml();

var result = someObj;
if (name != null)
    result = result.Where(i => i.Name == name);
if (city != null)
    result = result.Where(i => i.City == city);
if (state != null)
    result = result.Where(i => i.State == state);

De cette façon, vous appliqueriez n'importe quel nombre de filtres (de aucun aux trois), selon ce qui est réellement spécifié dans votre XML.

5
Douglas

Oui, c'est en fait assez simple:

var name = GetBobNameFromXml();
var result = someObj.Where(i => i.Name == name);

Vous pouvez également choisir d'appliquer ou non des critères au coup par coup.

var result = someObj;
var name = xmlCriteria.Name;
if(!string.IsNullOrEmpty(name))
{
    result = result.Where(i => i.Name == name);
}
// follow the same pattern for city, state, etc.

Vous pouvez même utiliser un modèle qui utilise un dictionnaire à clé de nom de fonctions de critère, pour éviter un tas d'instructions if.

foreach(var criterionPair in xmlCriteria)
{
    var value = criterionPair.Value;
    result = result.Where(i => propGetters[criterionPair.PropertyName](i, value));
}

Fondamentalement, il y a beaucoup à faire dans ce sens. Si vous souhaitez une réponse plus spécifiquement adaptée à votre situation, vous devrez fournir une question plus spécifique.

3
StriplingWarrior