Domanda

che voglio ottenere quanto segue in LINQ to Entities:

Ottieni tutte le richieste che non hanno alcuna applicazione o l'applicazione dispone di uno status! = 4 (Completato)

select e.*
from Enquiry enq
left outer join Application app
 on enq.enquiryid = app.enquiryid
where app.Status <> 4 or app.enquiryid is null

Qualcuno ha fatto prima senza utilizzare DefaultIfEmpty (), che non è supportato da LINQ to Entities?

Sto cercando di aggiungere un filtro a una query IQueryable in questo modo:

IQueryable<Enquiry> query = Context.EnquirySet; 

query = (from e in query 
         where e.Applications.DefaultIfEmpty()
                             .Where(app=>app.Status != 4).Count() >= 1 
         select e);

Grazie Mark

È stato utile?

Soluzione

Fare questo:

IQueryable<Enquiry> query = Context.EnquirySet; 

query = (from e in query 
         where (!e.Applications.Any()) 
               || e.Applications.Any(app => app.Status != 4)
         select e);

Non trovo la gestione di LINQ del problema di quello che sarebbe un "outer join" in SQL "goofy" a tutti. La chiave per comprendere è pensare in termini di un oggetto grafico con proprietà Null piuttosto che un set di risultati in tabella.

Qualsiasi () mappe per esiste in SQL, quindi è molto più efficiente di Conte () in alcuni casi.

Altri suggerimenti

In EF 4.0+, LEFT JOIN sintassi è un po 'diverso e presenta un capriccio folle:

var query = from c1 in db.Category 
        join c2 in db.Category on c1.CategoryID equals c2.ParentCategoryID  
        into ChildCategory 
        from cc in ChildCategory.DefaultIfEmpty() 
        select new CategoryObject  
        { 
            CategoryID = c1.CategoryID,  
            ChildName = cc.CategoryName 
        } 

Se si cattura l'esecuzione di questa query in SQL Server Profiler, si vedrà che per davvero effettuare un LEFT OUTER JOIN. Tuttavia, se si hanno lasciato Unione multipla ( "gruppo Iscriviti") clausole nella query LINQ-to-entità, ho trovato che la clausola di self-join può realmente eseguire come in JOIN INNER - ANCHE NEL CASO IN CUI SOPRA sintassi è usata

La risoluzione a questo? Per quanto folle e, secondo MS, sbagliato come sembra, ho risolto questo cambiando l'ordine delle clausole di aderire. Se l'autoreferenziale LEFT JOIN clausola è stato il 1 ° Gruppo LINQ registrazione, SQL Profiler ha segnalato un INNER JOIN. Se l'autoreferenziale LEFT JOIN clausola è stata l'ultimo gruppo LINQ registrazione, SQL Profiler ha segnalato un LEFT JOIN.

Grazie ragazzi per il vostro aiuto. Sono andato per questa opzione, alla fine, ma le tue soluzioni hanno aiutato ad ampliare la mia conoscenza.

IQueryable<Enquiry> query = Context.EnquirySet;

query = query.Except(from e in query
                     from a in e.Applications
                     where a.Status == 4
                     select e);

A causa di Linq di Goofy (lettura non standard) modo di gestire outers, è necessario utilizzare DefaultIfEmpty ().

Che cosa farete è gestito tuoi LINQ to Entities query in due IEnumerables, poi LEFT JOIN utilizzando DefaultIfEmpty (). Può sembrare qualcosa di simile:

IQueryable enq = Enquiry.Select();
IQueryable app = Application.Select();
var x = from e in enq
join a in app on e.enquiryid equals a.enquiryid
into ae
where e.Status != 4
from appEnq in ae.DefaultIfEmpty()
select e.*;

Solo perché non è possibile farlo con LINQ to Entities non significa che non si può farlo con LINQ crudo.

(Nota:..? Prima che qualcuno me downvotes ... sì, lo so che ci sono modi più eleganti per fare questo sto solo cercando di renderlo comprensibile E 'il concetto che è importante, a destra)

Un'altra cosa da considerare, se si fa riferimento direttamente nessun alloggio nel vostro clausola in cui da un gruppo di sinistra incollati (usando l'nella sintassi) senza controllare nulla, Entity Framework sarà ancora convertire il LEFT JOIN in un INNER JOIN.

Per evitare questo, filtrare da parte "da x in leftJoinedExtent" della query in questo modo:

var y = from parent in thing
        join child in subthing on parent.ID equals child.ParentID into childTemp
        from childLJ in childTemp.Where(c => c.Visible == true).DefaultIfEmpty()
        where parent.ID == 123
        select new {
            ParentID = parent.ID,
            ChildID = childLJ.ID
        };

ChildID nel tipo anonimo sarà un tipo nullable e la query questo genera sarà un LEFT JOIN.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top