2015-08-21 27 views
14

Sto memorizzando alcuni dati di filtro nella mia tabella. Consentitemi di chiarire meglio: voglio memorizzare alcune clausole where e i loro valori in un database e usarli quando voglio recuperare i dati da un database.Entity Framework filtra i dati per stringa sql

Ad esempio, consideriamo un people tavolo (insieme di entità) e alcuni filtri su di esso in un altro tavolo:

"age" , "> 70" 
"gender" , "= male" 

Ora, quando posso recuperare i dati dalla tabella people voglio ottenere questi filtri per filtrare i miei dati .

So che posso generare una query SQL come una stringa ed eseguirla, ma c'è un altro modo migliore in EF, LINQ?

+0

Con il framework entità è possibile utilizzare la funzione Where in questo modo: ob.Where (p => p.age> 70 && gender == "male"). – MaticDiba

+0

l'età e i 70 sono filtri di stringa che vengono recuperati dal DB. quindi, come posso scrivere questa riga di codice?Leggi di nuovo la domanda per favore. Grazie. – ConductedClever

+0

Puoi usare questo [expression builder] (http://www.codeproject.com/Tips/582450/Build-Where-Clause-Dynamically-in-Linq) –

risposta

8

Una soluzione è quella di utilizzare Dynamic Linq Library, usando questa libreria si può avere:

filterTable = //some code to retrive it 
var whereClause = string.Join(" AND ", filterTable.Select(x=> x.Left + x.Right)); 
var result = context.People.Where(whereClause).ToList(); 

Supponendo che tabella filtro ha colonne Left e Right e si desidera unire i filtri per AND.

mio suggerimento è di includere ulteriori dati nella tabella di filtro, ad esempio separare gli operatori operandi e aggiungere una colonna che determina il join è And o OR ed una colonna che determina l'altra riga che unisce questa. Hai bisogno di una struttura ad albero se vuoi gestire query più complesse come (A and B)Or(C and D).

Un'altra soluzione è creare un albero di espressioni dalla tabella dei filtri. Ecco un semplice esempio:

var arg = Expression.Parameter(typeof(People)); 
Expression whereClause; 
for(var row in filterTable) 
{ 
    Expression rowClause; 
    var left = Expression.PropertyOrField(arg, row.PropertyName); 
    //here a type cast is needed for example 
    //var right = Expression.Constant(int.Parse(row.Right)); 
    var right = Expression.Constant(row.Right, left.Member.MemberType); 
    switch(row.Operator) 
    { 
      case "=": 
       rowClause = Expression.Equal(left, right); 
      break; 
      case ">": 
       rowClause = Expression.GreaterThan(left, right); 
      break; 
      case ">=": 
       rowClause = Expression.GreaterThanOrEqual(left, right); 
      break; 
     } 
     if(whereClause == null) 
     { 
      whereClause = rowClause; 
     } 
     else 
     { 
      whereClause = Expression.AndAlso(whereClause, rowClause); 
     } 
} 
var lambda = Expression.Lambda<Func<People, bool>>(whereClause, arg); 
context.People.Where(lambda); 

questo è esempio molto semplificato, si dovrebbe fare molti convalide tipo casting e ... al fine di rendere questo funziona per tutti i tipi di query.

+3

Il tuo esempio aiuterà enormemente OP a visualizzare ciò che deve essere fatto. Lasciatemi solo suggerire qualcosa ai lettori interessati per capire il loro prossimo passo: considera il [modello interprete] (https://en.wikipedia.org/wiki/Interpreter_pattern) o il [modello visitatore] (https: //en.wikipedia .org/wiki/Visitor_pattern) ([confronto] (http://www.researchgate.net/profile/Tijs_Van_der_Storm/publication/220878226_A_Case_of_Visitor_versus_Interpreter_Pattern/links/09e4150981f71beda3000000.pdf)). Questo di solito rende un design più facilmente mantenibile, ma l'idea è la stessa naturalmente. – tne

+0

Entrambe le tue risposte sono brillanti. ma penso che mi piace il secondo di più. Molte grazie. – ConductedClever

+0

Prego. Il secondo è più impegnativo, mi congratulo con te per il tuo coraggio !! –

3

Questa è una domanda interessante. Prima di tutto, assicurati di essere onesto con te stesso: stai creando un nuovo linguaggio di query, e questo è non un compito banale (per quanto banali possano sembrare le tue espressioni).

Se sei certo di non sottovalutare l'attività, allora ti consigliamo di guardare LINQ expression trees (reference documentation).

Sfortunatamente, è un argomento abbastanza ampio, vi incoraggio ad imparare le basi e a porre domande più specifiche man mano che si presentano. L'obiettivo è interpretare i record di espressione del filtro (recuperati dalla tabella) e creare un albero di espressioni LINQ per il predicato che rappresentano. È quindi possibile passare l'albero alle chiamate Where() normalmente.

2

Senza sapere che cosa l'interfaccia utente si presenta come qui è un semplice esempio di cosa stavo parlando nei miei commenti riguardo Serialize.Linq biblioteca

public void QuerySerializeDeserialize() 
    { 
      var exp = "(User.Age > 7 AND User.FirstName == \"Daniel\") OR User.Age < 10"; 
      var user = Expression.Parameter(typeof (User), "User"); 
      var parsExpression = 
        System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] {user}, null, exp); 

      //Convert the Expression to JSON 
      var query = e.ToJson(); 

      //Deserialize JSON back to expression 
      var serializer = new ExpressionSerializer(new JsonSerializer()); 
      var dExp = serializer.DeserializeText(query); 

      using (var context = new AppContext()) 
      { 
       var set = context.Set<User>().Where((Expression<Func<User, bool>>) dExp); 
      } 

    } 

Probabilmente si potranno ottenere più elaborato utilizzando la riflessione e invocando la query LINQ generica basata su i tipi che arrivano dall'espressione. In questo modo puoi evitare di trasmettere l'espressione come ho fatto alla fine dell'esempio.