2009-08-20 4 views
4

J'ai un projet qui me demande de faire un tel moteur de recherche mais qui est tout dynamique. Je veux dire que je peux avoir environ 0 à 9 "groupe" principal qui a quelque chose comme une possibilité infinie de "où" avec "OU" ou "ET". La première chose que nous pensons était d'utiliser Dynamic Linq qui fournit une bonne alternative pour construire une requête dynamique. Tout cela en utilisant EF avec un emballage maison.Dynamic LINQ sur une collection?

Problème: Je ne peux pas accéder à une «collection». Je veux dire, je peux accéder facilement à un objet référencé (comme Customer.State.StateName = "New-York" OU Custoemr.State.StateName = "Quebec") mais je ne peux pas trouver un moyen d'accéder à quelque chose comme : "Customer.Orders.OrderID = 2 OU Customer.Orders.OrderID = 3". Je peux facilement comprendre cela parce que c'est une collection, mais comment puis-je faire cela?

S'il vous plaît aidez-moi !!

** Désolé pour mon anglais !!


Mise à jour

Je ne suis pas clair, je pense enought, désolé parce im son français ...

Mon problème parce que rien ne l'est statique. C'est un moteur de recherche de candidats pour une entreprise qui recrute des candidats dans une entreprise. Dans une page où le manager peut rechercher un candidat, il peut "analyser" par: Domaine (s) (Jobs), Ville (s) ou bien d'autres utilisateurs que l'utilisateur a remplis lors de son inscription. Tout ceci dans le format (si c'était en SQL):

[...] OERE (domaine.domaineID = 3 OU domaine.domaineID = 5 OU domaine.domaineID = 23) ET (cities.cityID = 4, villes .ville = 32) [...]

donc je ne peux pas le faire avec un format LINQ normal comme:

Candidat.Domaines.Where(domain => domain.DomainID == 3 || domain.DomainID == 5 || domain.DomainID == 23); 

Même l'opérateur dans les paretheses sont dynamiques ("ET" ou « oU ")! C'est pourquoi nous essayons d'utiliser Dynamic Linq parce que c'est beaucoup plus flexible.

Espoir il est plus facile à comprendre mon problème ...


Mise à jour 2 Voici ma méthode

private string BuildDomainsWhereClause() { 
     StringBuilder theWhere = new StringBuilder(); 

     if (this.Domaines.NumberOfIDs > 0) { 
      theWhere.Append("("); 

      theWhere.Append(string.Format("Domaines.Where(")); 
      foreach (int i in this.Domaines.ListOfIDs) { 
       if (this.Domaines.ListOfIDs.IndexOf(i) > 0) { 
        theWhere.Append(string.Format(" {0} ", this.DispoJours.AndOr == AndOrEnum.And ? "&&" : "||")); 
       } 
       theWhere.Append(string.Format("DomaineId == {0}", i)); 
      } 
      theWhere.Append("))"); 
     } 

     return theWhere.ToString(); 
    } 

Il fonctionne très bien au lieu que "renvoie pas un booléen". Alors, comment dois-je? Erreur: "Expression de type" Boolean "attendue".

A la fin, il retourne quelque chose comme: "(Domaines.Where (DomaineId == 2 & & DomaineId == 3 & & DomaineId == 4 & & DomaineId == 5))." qui est ajouté à ma requête LINQ:

var queryWithWhere = from c in m_context.Candidats.Where(WHERE) 
            select c; 

Ne pas oublier qu'il ya comme 7 ou 8 plus « possible » a ajouté des choses à rechercher dans ... Des idées?

Répondre

5

Ce que vous devez faire ici, est de construire un LambdaExpression (plus précisément un Expression<Func<T, bool>>). Vous ne pouvez pas utiliser une chaîne. Vous pouvez construire une simple expression comme ceci:

ParameterExpression p = Expression.Parameter(typeof(Domaine), "domaine"); 
Expression<Func<Domaine, bool>> wherePredicate = 
    Expression.Lambda<Func<Domaine, bool>>(
    Expression.Or(
     Expression.Equal(
     Expression.Property(p, "DomainID"), 
     Expression.Constant(10)), 
     Expression.Equal(
     Expression.Property(p, "DomainID"), 
     Expression.Constant(11)) 
    ), p); 

dire,

domaine.DomainID = 10 || domaine.DomainID = 11

Pas très lisible si vous avez besoin de le faire à la main.

Il y a un échantillon d'un analyseur d'expression pleinement opérationnel qui fera réellement pour vous basé sur une chaîne en C# Samples for Visual Studio 2008 à MSDN Code Gallery, sous DynamicQuery. (Le contrôle LinqDataSource utilise une version légèrement modifiée de cet exemple en interne.)

+0

Merci beaucoup. Ce n'est pas exactement ce à quoi je m'attends, mais ça a l'air génial. J'ai encore quelques trucs pour le rendre parfaitement dynamique. Mais merci, très utile. –

1

En supposant que le client.Commandes renvoie une collection, c'est exactement pourquoi vous ne pouvez pas simplement appeler une propriété de celui-ci.

Pour utiliser LINQ pour obtenir l'ordre que vous cherchez, vous aurez besoin de connaître le OrderID (ou une autre propriété) dans ce cas, vous pouvez faire:

Customer.Orders.Find(order => order.OrderID == 2); 

Edit: Pour ajouter l'expression à trouver id 2 ou 3 ainsi:

Customer.Orders.FindAll(order => order.OrderID == 2 || order.OrderID == 3); 
1

Dois-je comprendre ce droit, que les deux clients est une collection et commandes est une collection tout Etat (évidemment) est une propriété?

var q = from a in Customer 
    from b in a.Orders 
    where b.ID == 2 
       || b.ID == 3 
    select b; 

Travaillerais je suppose.

Modifier:

je l'ai fait en partie quelque chose comme ça. Il a été trop longue pour être exactement comment je l'ai fait, mais je peux vous dire, que j'utilisais

public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values); 

De classe DynamicQueryable.

this.CountrySitesObject.Sites.AsQueryable().Where(w.WhereQuery, w.WhereParameters) 

(copié à partir de mon code).

+0

Oui, cela fonctionne très bien. Mais pas quand vous ne savez pas vraiment combien "b.Id" vous devez rechercher. Même pas si c'est un "||" ou "&&" entre. –

+0

Je vais essayer aussi. Mais je suis sur une solution qui semble fonctionner. Je reviendrai plus tard pour vous donner des nouvelles. –

0

Si vous revenez en arrière et demandez ce que le client veut faire.

Filter bug information. 

Pourquoi ne pas exporter les données vers Excel ou d'un point Excel pour la table SQL. Ce n'est pas aussi amusant à construire, mais vous le feriez dans quelques heures, au lieu de jours ou de semaines. :)

+0

Oui, je sais! Mais nous avons pensé que Dynamic LINQ faisait exactement ce que nous cherchions ... –

3

Enfin, je l'ai exactement comme je le veux.

private string BuildDomainsWhereClause() { 
     StringBuilder theWhere = new StringBuilder(); 

     if (this.Domains.NumberOfIDs > 0) { 
      theWhere.Append("("); 

      foreach (int i in this.Domains.ListOfIDs) { 
       if (this.Domains.ListOfIDs.IndexOf(i) > 0) { 
        theWhere.Append(string.Format(" {0} ", this.Domains.AndOr == AndOrEnum.And ? "&&" : "||")); 
       } 
       theWhere.Append(string.Format("Domains.Any(IdDomaine== {0})", i)); 
      } 
      theWhere.Append(")"); 
     } 

     return theWhere.ToString(); 
    } 

qui produisent quelque chose comme: "(DispoJours.Any (IdDispo == 3) & & DispoJours.Any (IdDispo == 5))".

Tous mes autres "Où constructeur" feront les mêmes choses avec un "& &" entre lesquels donner le bon résultat.

Et plus tard:

var queryWithWhere = from c in m_context.Candidats.Where(WHERE) 
        select c; 

WHOOOHOOO !! Merci les amis. Étaient très utiles! J'adore ce site!


Mise à jour

Ne pas oublier que j'utiliser LINQ dynamique sur cette requête. Ce n'est pas une requête LINQ normale.

+2

Si vous créez des requêtes réelles avec des chaînes, assurez-vous de paramétrer les chaînes, ou vous pourriez être vulnérable aux attaques par injection SQL. Bien que ce soit le moyen le plus facile, parfois ce n'est pas nécessairement le meilleur/le plus sûr. Si vous utilisez LINQ pour vos requêtes, il paramètrera automatiquement les requêtes pour vous. – MunkiPhD

+0

Merci beaucoup de m'avoir empêché. Maintenant que nous n'utilisons plus SQL, j'ai oublié les choses dangereuses. Merci. Mais dans mon cas, l'utilisateur n'écrit pas "1", il le sélectionne dans une checkboxlist pour que le danger ne soit pas vraiment là. Je le ferai de toute façon, mais ne constituait pas vraiment un danger. –

Questions connexes