3 votes

Construction d'une clause where dynamique, Linq To Sql

J'utilise EF Code first 4.2, Quelle solution proposez-vous lorsque la clause where doit être construite dynamiquement ? Pourtant, la fonctionnalité Include serait fortement requise :

var results = db.Set<dynamicType>.Where("dynamic conditions").Include("....");

La condition dynamique ci-dessus doit consulter une autre table pour filtrer les enregistrements : Si je voulais écrire cela en expression Linq, ce serait quelque chose comme :

var result = db.Set<Contact>().Where(c=>c.AccountId == _Id_param || db.Set<LinkTable>().Any(a=>a.FkFieldId == c.AccountId && a.ParentId == _Id_param)).Include("Quotes");

J'ai essentiellement besoin de la linq dynamique de l'expression ci-dessus, car pour différents types, les champs de la clause Where changent (Contact n'est qu'un exemple), par exemple dans un modèle le champ FK peut être "AccountId" et dans un autre il doit être "AccountFKId". La clause Where doit donc être dynamique !

3voto

Ladislav Mrnka Points 218632

IQueryable est composable, ce qui vous permet de construire des requêtes à la volée :

var query = db.Set<Contact>().Include(...);

if (something) 
{
    query = query.Where(...);
}

// Other wheres

Linq est fortement typé, vous devez donc toujours savoir avec quel type vous allez commencer dans votre fichier Set<> appel. Vous pouvez le rendre générique mais pas dynamique (à moins que vous ne l'écriviez entièrement par réflexion).

Vous pouvez utiliser linq dynamique pour définir des conditions de présence avec des chaînes de caractères, mais encore une fois, vous devrez au moins connaître le type pour Set<> .

1voto

sam360 Points 252

UPDATE

J'ai pu résoudre le problème en modifiant directement l'arbre d'expression.

En utilisant une idée de Le blog de TomasP a beaucoup aidé :

La solution consistait à créer un deuxième IQueryable pour la requête interne, puis à le transmettre comme expression à l'expression IQueryable du modèle dynamique existant.

IQueryable<LinkTable> linkQuery = db.Set<LinkTable>().AsQueryable();

MethodCallExpression internalQueryWhere = Expression.Call(typeof(Queryable), "Where", new Type[] { linkQuery.ElementType }, linkQuery.Expression,Expression.Lambda<Func<LinkTable, bool>>(myfilters, new ParameterExpression[] { filterParameter })); 

linkQuery = linkQuery.Provider.CreateQuery<LinkTable>(internalQueryWhere);

Expression anyMethodExpr = Expression.Call(typeof(Queryable), "Any", new Type[] { linkQuery.ElementType }, linkQuery.Expression);

Vous pouvez maintenant passer l'expression anyMethodExpr à la clause where de l'entité originale IQueryable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X