2012-09-13 7 views
6

Attualmente sto utilizzando il framework Entity, ma si tratta di un problema "condiviso" tra tutti gli ORM e persino IEnumerable.Come filtrare IEnumerable in base a un parametro di input dell'entità

Diciamo che ho un metodo MVC si presenta così:

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(???).ToList(); 
    return View(data); 
} 

voglio interrogare il contesto in base al parametro di ingresso come:

var data = context.Foo.Where(x => x.Date == model.Date && 
          x.Name == model.Name && 
          x.ItemCode = model.ItemCode).ToList(); 

ma è più complicato di così, perché se uno dei parametri sopra (Date \ Name \ ItemCode) è nullo, non voglio includerlo all'interno della query.
Se ho codificare il possibile simile a questo:

var query = context.Foo; 

if (model.Date != null) 
    query =query.Where(x => x.Date == model.Date); 

if (model.ItemCode != null) 
    query =query.Where(x => x.ItemCode == model.ItemCode); 
... 

Ci deve essere un modo più semplice di questo.
Ho bisogno di un modo per generare un'espressione del tipo Expression<T, bool> da utilizzare nel metodo Dove.

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(THE_EXPRESSION).ToList(); 
    return View(data); 
} 

Esiste un modo integrato per creare quell'espressione? C'è un pacchetto in nuget che lo fa?


Aggiornamento: Ci potrebbero essere più di 30 properites nel modello-entità; scrivere 30 volte il Dove per ogni domanda può essere un dolore al collo:

.Where(model.Date != null, x => x.Date == model.Date) 
.Where(model.Name != null, x => x.Name == model.Name) 
.Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
... 
... 
... 
.ToList(); 

risposta

5

Provalo. Questo sta usando riflessioni ed espressioni per costruire dinamicamente la query. L'ho provato solo con gli oggetti.

static IQueryable<T> Filter<T>(IQueryable<T> col, T filter) 
{ 
    foreach (var pi in typeof(T).GetProperties()) 
    { 
     if (pi.GetValue(filter) != null) 
     { 
      var param = Expression.Parameter(typeof(T), "t"); 
      var body = Expression.Equal(
       Expression.PropertyOrField(param, pi.Name), 
       Expression.PropertyOrField(Expression.Constant(filter), pi.Name)); 
      var lambda = Expression.Lambda<Func<T, bool>>(body, param); 
      col = col.Where(lambda); 
     } 
    } 

    return col; 
} 
+0

Un esempio che mostra come verrà utilizzato questo metodo sarà molto utile. – devinbost

5

Il tuo metodo hard coded è il metodo migliore in generale.

Tuttavia, puoi provare a semplificarti la vita scrivendo un metodo di estensione appropriato per mantenere pulito il codice.

Prova questa ad esempio:

public static class QueryableEx 
{ 
    public static IQueryable<T> Where<T>(
     this IQueryable<T> @this, 
     bool condition, 
     Expression<Func<T, bool>> @where) 
    { 
     return condition ? @this.Where(@where) : @this; 
    } 
} 

Ora si potrebbe scrivere questo codice:

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    using (var context = new Context()) 
    { 
     var data = context.Foo 
      .Where(model.Date != null, x => x.Date == model.Date) 
      .Where(model.Name != null, x => x.Name == model.Name) 
      .Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
      .ToList(); 
     return View(data); 
    } 
} 

(non dimenticate di smaltire vostro contesto o utilizzare using di farlo per voi.)

+0

+1 Questo ottiene il mio voto - schermate che consentono all'utente di cercare un grande tavolo di N! diverse permutazioni lo rendono un incubo da indicizzare a livello db. Rendendo ogni filtro visibile allo sviluppatore, c'è almeno una certa visibilità nella query risultante, e può causare un ripensamento su quali campi (o combinazioni di questi) possono essere esposti all'utente. – StuartLC

+0

Grazie per l'input e l'idea.Ma se la mia entità modello ha più di ** 30 ** properites scrive 30 volte Dove (...) può essere un dolore. – gdoron

+0

@gdoron - Sì, ma devi scriverli da qualche parte. Se provi a farlo con la riflessione e la costruzione di espressioni, temo che ora avresti due problemi. – Enigmativity

1

Penso che dovresti incapsulare la tua logica nella tua entità Foo, ad es.

public Foo 
    { 
    public bool isMatch(Model model) 
    { 
     // check your rules and return result 
    } 
    } 

e usarlo in linq. Oppure guarda Specification pattern

+1

Questo funziona solo con LINQ su oggetti, non con Entity Framework. –

+0

È possibile restituire Espressione pubblica > IsSatisfiedBy() – syned

+0

Che blocca completamente la propria entità. –

Problemi correlati