2008-09-24 7 views
17

Ich bin mir nicht sicher, ob das möglich ist oder ob ich richtig ausdrücken kann, wonach ich suche, aber ich habe das folgende Stück Code immer wieder in meiner Bibliothek und möchte etwas DRY üben. Ich habe eine Reihe von SQL Server-Tabellen, die ich abfrage, basierend auf einem einfachen benutzerdefinierten Suchfeld ala Google. Ich verwende LINQ, um die endgültige Abfrage basierend auf dem Inhalt der Suchzeichenfolge zu erstellen. Ich bin auf der Suche nach einer Möglichkeit, Generika zu verwenden und in Lambda-Funktionen übergeben aus diesem eine wiederverwendbare Routine zu erstellen:Generisches LINQ-Abfrageprädikat?

string[] arrayOfQueryTerms = getsTheArray(); 

var somequery = from q in dataContext.MyTable 
       select q; 

if (arrayOfQueryTerms.Length == 1) 
{ 
    somequery = somequery.Where<MyTableEntity>(
     e => e.FieldName.StartsWith(arrayOfQueryTerms[0])); 
} 
else 
{ 
    foreach(string queryTerm in arrayOfQueryTerms) 
    { 
     if (!String.IsNullOrEmpty(queryTerm)) 
     { 
      somequery = somequery 
         .Where<MyTableEntity>(
          e => e.FieldName.Contains(queryTerm)); 
     } 
    } 
} 

Ich hatte gehofft, eine generische Methode mit der Signatur zu erstellen, die wie etwas aussieht:

private IQueryable<T> getQuery(
    T MyTableEntity, string[] arrayOfQueryTerms, Func<T, bool> predicate) 

Ich benutze die gleiche Suchstrategie über alle meine Tabellen, so ist das einzige, was wirklich von der Nutzung unterscheidet, die MyTable & MyTableEntity gesucht und der FieldName gesucht. Macht das Sinn? Gibt es eine Möglichkeit mit LINQ, den Namen des Feldes, das in der WHERE-Klausel abgefragt werden soll, dynamisch weiterzugeben? Oder kann ich das als Prädikat Lambda weitergeben?

e => e.FieldName.Contains(queryTerm) 

ich erkennen, dass es eine Million und eine halbe Möglichkeit, dies in SQL zu tun, wahrscheinlich einfacher, aber ich würde gerne alles in der LINQ-Familie für diesen zu halten. Außerdem finde ich, dass Generika für ein Problem wie dieses hilfreich sein sollten. Irgendwelche Ideen?

+0

Gleiche Frage, aber für Select-Klausel: http://StackOverflow.com/Questions/10376947/How-CanI-Construct-and-Save-To-A-D-Bo-For-later-use-a-Semi- arbitrary-lambda-expre –

Antwort

15

Es klingt wie Sie für die dynamische Linq suchen. Werfen Sie einen Blick here. Auf diese Weise können Sie Zeichenfolgen als Argumente an die Abfragemethoden zu übergeben, wie:

var query = dataSource.Where("CategoryID == 2 && UnitPrice > 3") 
         .OrderBy("SupplierID"); 

Edit: Ein anderer Satz von Beiträge zu diesem Thema, C# 4 Dynamic Unterstützung mit: Part 1 und Part 2.

+0

Vielen Dank! Sehr cool, ich muss alle Blogbeiträge von ScottGu zu diesem Thema durchsehen ... – Codewerks

+0

Leider habe ich nur den einen gefunden - ich dachte, er hätte eine Serie, aber ich glaube ich lag falsch. Es gibt jedoch andere Informationsquellen. –

+0

Entschuldigung, eine Frage hier zu stellen. Was ist Prädikat und wie ist es mit Linq verwandt? – Thomas

5

Sie könnten Ausdruck Bäume aussehen wollen:

IQueryable<T> getQuery<T>(T myTableEntity, string[] arrayOfQueryTerms, Expression<Func<T, bool>> predicate) 
{ var fieldOrProperty = getMemberInfo(predicate); 
    /* ... */ 
} 

MemberInfo getmemberInfo<T>(Expression<Func<T,bool> expr) 
{ var memberExpr = expr as MemberExpression; 
    if (memberExpr != null) return memberExpr.Member; 
    throw new ArgumentException(); 
} 

var q = getQuery<FooTable>(foo, new[]{"Bar","Baz"}, x=>x.FieldName); 
+0

Ich denke, dass die Dynamische LINQ Antwort ist, was ich gehen werde, aber danke dafür werde ich auch versuchen, dies morgen durchzuarbeiten. – Codewerks

0

ich diese gleiche Sache vor kurzem zu tun hatte. Sie benötigen Dynamic Linqhere ist eine Möglichkeit, dies stark typisiert zu halten.