2010-03-09 5 views
3

J'ai une interface qui ressemble à ce qui suit:Get prédicats <T> Info propriété

public IEnumerable<IDocument> Search(Predicate<IDocument> predicate) { ... } 

où un IDocument ressemble à ceci:

public interface IDocument 
{ 
    string Id {get; set;} 
    string Title {get; set;} 
    ... 
} 

Je suis sur le point de mettre en œuvre un fournisseur de documents où je dois décomposer le contenu du Predicate et extrayez les propriétés afin de créer une chaîne SQL pour une base de données de documents pour laquelle nous n'avons actuellement aucun mappage OR/M. Un exemple: Je veux savoir si l'utilisateur recherche par ID ou par titre, donc je sais si je peux effectuer une recherche par ID ou si je dois effectuer une recherche LIKE sur le titre. J'ai toujours beaucoup utilisé LINQ mais c'est la première fois que je suis assis à l'autre bout du pipeline ... J'ai lu un peu sur Expression trees et Reflection mais les morceaux ne sont pas tombés en place pour le moment. Comment (si?) Puis-je décomposer/refléter le prédicat afin d'obtenir une liste de paramètres que je peux concaténer en une chaîne SQL? Je cherche quelque chose comme ce croquis:

public IEnumerable<IDocument> Search(Predicate<IDocument> predicate) 
{ 
    string id = DoSomeMagic(predicate, "Id"); 
    string title = DoSomeMagic(predicate, "Title"); 
    if (!string.isNullOrEmpty(id)) 
     ...make ID search 
    else 
     ...search by title 
} 

Avertissement: Le fournisseur est un ancien système inhouse lié au remplacement de cet automne qui rend SQL en ligne un bon choix; o)

Répondre

1

Vous ne pouvez pas facilement le prédicat introspect. Peut-être que vous devriez envisager de changer votre conception en plus ad hoc de type sous-jacente, une interface sous-jacente plus spécifique:

public interface IDocument 
    { 
     string Id {get; set;} 
     string Title {get; set;} 
    } 
    public class SearchCriteria 
    { 
     public Nullable<int> Id; 
     public string Title; 
    } 
    public IEnumerable<IDocument> Search(SearchCriteria predicate) 
    { 
     if (predicate.Id.HasValue) 
      //...make ID search 
     else if (!string.IsNullOrEmpty(predicate.Title)) 
      //...search by title 
     else 
      // other kind of search 
    } 

Remplacer les champs publics avec des attributs, mettre la logique de recherche dans le SearchCriteria (par exemple .GetResult() ou. GetSQLQuery()) et cela peut convenir à votre système, en supposant que vous puissiez connaître tous les critères de recherche disponibles.

+0

C'est ce que nous avons décidé faire. L'arbre d'expression que nous devrions construire deviendrait extrêmement complexe, donc nous nous sommes rapprochés d'un prédicat et utilisons une approche plus KISS. – kerbou

3

Vous ne pouvez pas faites ceci avec des prédicats ou des délégués. Ils sont compilés et il n'est pas possible d'obtenir des informations sur ce qu'il fait. Vous avez vraiment besoin de Expression arbres pour cela, mais l'analyser vous-même peut être difficile. Vous seriez mieux d'utiliser un outil O/RM.

Lorsque vous utilisez une expression avec LINQ to SQL, par exemple, la construction de votre méthode de recherche sera un jeu d'enfant:

public IEnumerable<Document> Search(
    Expression<Func<Document, bool>> predicate) 
{ 
    using (db = new DocumentDataContext()) 
    { 
     return db.Documents.Where(predicate).ToArray(); 
    } 
} 
0

Vous devez déclarer votre méthode comme acceptant une expression> à la place. Cette expression peut être introspectée (bien qu'il y ait beaucoup de choses différentes).

Essayez d'exécuter ce qui suit dans LINQPad (LINQPad fournit la méthode d'extension de vidage, qui permet de visualiser l'expression très bien)

void Main() 
{ 
    show(x=>x.Length==5); 
} 

void show(Expression<Predicate<string>> e){ 
    e.Dump(); 
} 

Vous pouvez exécuter une expression en appelant Compile premier

Questions connexes