2013-08-09 8 views
5

Consente di dire che abbiamo:LINQ espressione per filtrare l'elenco della collezione di entità, e mantenere la lista delle entità

public class Foo 
{ 
    public long Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Bar> { get; set; } 
} 

public class Bar 
{ 
    public long Id { get; set; } 
    public int Age { get; set; } 

    public virtual Foo { get; set; } 
    public long FooId { get; set; } 
} 

I nostri dati possono essere simile a questa: (assumere List<Foo>)

// Forget the syntax, just to demonstrate data 
foo[0] = new Foo{ Id = 1, Name = "A", Bar = { collection of Bars with Ages over 10 }}; 
foo[1] = new Foo{ Id = 2, Name = "B", Bar = { collection of Bars with Ages over 20 }}; 
foo[2] = new Foo{ Id = 3, Name = "C", Bar = { collection of Bars with Ages under 10 }}; 

Ora, diciamo che volevo tutti quelli Foo s ma con il loro Bar s includendo solo uno Bar con un'età compresa tra 5-25.

Per qualcosa di simile, vorrei lavorare al contrario e ottenere tutte le barre, quindi ottenere tutti i Foos associati a quelle barre, e ri-mappare le barre di nuovo a Foo. Sembra troppo complicato di quanto dovrebbe essere.

Per essere più chiari - Tutti Foos con solo i loro bar con età compresa tra i 5 ei 25 :)

+0

http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b – Androiderson

+0

La tua domanda è una specie di poco chiara - vuoi tutto 'Foo's con solo il loro' Bar's con età tra 5 e 25 o vuoi solo i 'Foo's che hanno' Bar's con età tra 5 e 25? –

+0

Un modo, non ancora suggerito, è di implementare un metodo di estensione su Foo con una dichiarazione simile a: 'GetBarsBetween (int lower, int upper);' e usa semplicemente questo metodo di estensione per fare il filtraggio e il recupero delle barre corrette all'interno un Foo. Quindi puoi semplicemente selezionare tutti i Foo's 'where foo.GetBarsBetween (5, 25) .Any()'. Questo non richiede alcuna allocazione di memomry aggiuntiva o ristrutturazione degli oggetti attuali. Due svantaggi, non è possibile utilizzare semplicemente il codice esistente per lavorare con le barre filtrate e il tempo di calcolo è leggermente superiore. – Polity

risposta

4

Se si desidera selezionare tutti Foo 's e solo i loro Bar' s età compresa tra i di 5 e 25:

var results = 
    from f in db.Foos 
    select new 
    { 
     f.Id, 
     f.Name, 
     Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25) 
    }; 

Ciò produce un tipo anonimo come risultato. Se è necessario creare un tipo di nome (ad esempio se è necessario restituire il risultato da una funzione come List<T>) probabilmente si dovrebbe creare un semplice tipo di nome per questo set di risultati:

public class FooWithFilteredBarResult // replace with whatever name you like 
{ 
    public long Id { get; set; } 
    public string Name { get; set; } 
    public IEnumerable<Bar> { get; set; } 
} 


List<FooWithFilteredBarResult> results = 
    (from f in db.Foos 
    select new FooWithFilteredBarResult 
    { 
     Id = f.Id, 
     Name = f.Name, 
     Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25) 
    }) 
    .ToList(); 
+0

'let' ha un impatto piuttosto considerevole sulle prestazioni in linq sugli oggetti, basta fare un salto di qualità. – doogle

+0

La seconda risposta alle tue risposte è ciò che sto cercando. C'è un modo per evitare di dover specificare tutte le proprietà di Foo, invece di "selezionarli automaticamente" e mettere il condizionale sulle barre? – Josh

+0

@Josh No, sfortunatamente non c'è, anche se puoi sempre provare a filtrarli in seguito, ad es. mentre stai valutando i risultati. Inoltre devi solo specificare le proprietà di 'Foo' di cui hai bisogno. Se ci sono altre 50 proprietà a cui non ti importa, puoi lasciarle fuori. –

1
var r = Foos.Select(x => new Foo() 
     { 
      Id = x.Id, 
      Name = x.Name, 
      Bars = x.Bars.Where(y => y.Age <= 25 && y.Age >= 5).ToList() 
     }); 
+0

Questa è essenzialmente la stessa risposta di @pswg opzione # 2, ma non mi consente di creare un nuovo Foo? Dice che l'entità o il tipo complesso non possono essere costruiti in una query LINQ to Entities. – Josh

+0

@Josh sembra che abbiamo presentato allo stesso tempo. Hmm..non sapevo che stavi parlando di filtrare i record tramite EF. lemme pensaci. – zsong

1

Questo sarà anche selezionare solo Foo unico.

bars.Where(b => b.Age >= 5 && b.Age <= 25).GroupBy(b => b.FooId).Select(g => g.FirstOrDefault().Foo).ToList(); 
+0

Ottengo il GroupBy. Perché Select/FirstOrDefault? – Josh

+0

Per selezionare solo i Foo distinti, altrimenti si potrebbero finire con ripetizioni secondo la domanda e la struttura. – doogle

+0

Sembra che restituisca Bars? – Josh

Problemi correlati