2015-05-22 3 views
5

La configurazione che segue è vero:LINQ to Entity Framework: selezionare con un solo sottoinsieme di elementi figlio

  • A è classe genitore
  • A ha uno a molti di B
  • A ha uno a molti di C

  • B ha uno a molti di X

  • C ha sulla e per molti di X

  • X ha una proprietà chiamata DataFine: questo è i criteri di filtro

voglio recuperare un set che ha A, B, C e X (ABX e ACX Voglio filtrare il set in modo che vengano restituiti solo gli elementi che hanno X.EndDate = Date.

I non desidera elementi di X che non soddisfano questo criterio. Questo può essere fatto in un singolo Seleziona?

Attualmente sto cercando seguente codice:

var set = _context.Set<A>() 
    .Include("B.X") 
    .Include("C.X") 
    .Where(a => a.B.Any(b => b.X.Any(x => x.EndDate == date)) || 
       a.C.Any(c => c.X.Any(x => x.EndDate == date))) 
    .ToList(); 

Tuttavia, quando B.X è all'interno di criteri di filtro, includerà anche CX E quando uno dei B.X (X possono essere molti) è vera per i criteri , tornerà tutto B.X entità

ho fatto del mio meglio per fare un esempio:

A   B   X  X.EndDate 
A1   B1   BX1  2015-01-01 
A1   B1   BX2  2015-01-02 
A1   B2   BX3  2015-01-09 

A   C   X  X.EndDate 
A1   C1   CX1  2015-01-03 
A1   C1   CX2  2015-01-03 
A1   C2   CX3  2015-01-02 

When date == 2015-01-02 

Results are: 
A1 B1 BX1 
     BX2 
    B2 BX3 
    C1 CX1 
     CX2 
    C2 CX3 

Desired results are: 
A1 B1 BX2 
    C2 CX2 

Nota: Posso solo utilizzare questa notazione e non la notazione SQL-like. Ci sono più entità che devono essere incluse e questo può (apparentemente) essere fatto solo da .Include ("") con le virgolette

+0

Considerare la visualizzazione di un esempio di input, valori di output. –

+0

@HosseinNarimaniRad Fatto :) – Recipe

risposta

3

Che cosa si vuole fare è filtrare le tabelle inclusi e che non è qualcosa che Entity Framework supporta adesso: http://entityframework.codeplex.com/workitem/47. Se avete a che fare con le classi semplici allora si potrebbe un'istanza nuovo A nella vostra dichiarazione prescelta come questo:

var set = _context.Set<A>() 
    .Include("B.X") 
    .Include("C.X") 
    .Where(a => a.B.Any(b => b.X.Any(x => x.EndDate == date)) || 
       a.C.Any(c => c.X.Any(x => x.EndDate == date))) 
    .Select(a => new A() 
    { 
     B = a.B 
      .Where(b => b.X.Any(x => x.EndDate == DatePicker)) 
      .Select(b => new B() 
       { 
        X = b.X.Where(x => x.EndDate == DatePicker) 
       }), 
     C = a.C 
      .Where(c => c.X.Any(x => x.EndDate == DatePicker)) 
      .Select(c => new C() 
       { 
        X = c.X.Where(x => x.EndDate == DatePicker) 
       }) 
    }); 

Se le classi non sono così semplici, vale a direhai molte proprietà che dovresti mappare nella tua dichiarazione scelta o hai regole complesse di convalida aziendale, quindi la tua migliore possibilità potrebbe essere quella di continuare con la query che hai e semplicemente rimuovere le B, C e X che non vuoi da il set risultante prima di usarlo.

+0

Grazie per la risposta. Per curiosità: quando usi il primo .Seleziona, gli oggetti sono staccati dal contesto? In secondo luogo: prima di poter rimuovere gli elementi, non stai tracciando molti dati dal DB? Sospetto che le istruzioni di rimozione non siano parte della query originale? – Recipe

+0

In realtà, questa soluzione potrebbe essere completamente sbagliata, sfortunatamente. Sto confondendo LINQ con oggetti e LINQ con entità. Ulteriori ricerche suggeriscono che Entity Framework non ti consentirà di proiettare su un'entità mappata. Quindi, alla luce di ciò, la tua prima domanda è discutibile. –

+0

Per quanto riguarda la seconda domanda, sì, si otterrebbero più dati dal DB di quanto effettivamente necessario. Tuttavia, questo potrebbe non essere il problema principale. La tua prima domanda sembra implicare la tua intenzione di reinserire questi oggetti nel database ad un certo punto (presumo che sia per questo che sei preoccupato che vengano distaccati dal contesto). In tal caso, rimuovere i B, i C e gli X indesiderati non funzionerà comunque per te, in quanto l'EF sceglierebbe le delezioni come modifiche all'entità e persisterà tali modifiche nel DB. –

1

Qualcosa di simile?

from a in _context.Set<A>() 
from b in a.B 
from c in a.C 

let bx = b.X.Where(x => x.EndDate == date) 
let cx = c.X.Where(x => x.EndDate == date) 

where bx.Any() || cx.Any() 

select { a, b, c, bx, cx }; 

noti che si possono ottenere ripetuto a, b, e/o c nel set di risultati.

Aggiornamento
Se non è possibile utilizzare la sintassi LINQ, questo banalmente (anche se un pò brutto) si traduce in metodo di estensione chiama:

_context.Set<A>() 
.SelectMany(a => a.B, (a, b) => new { a, b, bx = b.X.Where(...) }) 
.SelectMany(x => x.a.C, (x, c) => new { x.a, x.b, x.bx, c, cx = c.X.Where(...) }) 
.Where(x => x.bx.Any() || x.cx.Any()) 
+0

Grazie per il suggerimento. Cosa succede se posso usare solo la notazione .Seleziona (come nel mio esempio) perché ci sono altri livelli in mezzo. Posso solo usare .include ("") con virgolette per consentire a tutte le entità di essere mappate correttamente. – Recipe

+0

Questa notazione LINQ si traduce banalmente in ".Seleziona" e vedi l'aggiornamento. –