2011-11-23 21 views
10

Sto provando a forzare Linq a preformare un inner join tra due tabelle. Darò un esempio.Forzare linq per eseguire join interni

CREATE TABLE [dbo].[People] (
    [PersonId] [int] NOT NULL, 
    [Name] [nvarchar](MAX) NOT NULL, 
    [UpdatedDate] [smalldatetime] NOT NULL 
    ... Other fields ... 
) 

CREATE TABLE [dbo].[CompanyPositions] (
    [CompanyPositionId] [int] NOT NULL, 
    [CompanyId] [int] NOT NULL, 
    [PersonId] [int] NOT NULL, 
    ... Other fields ... 
) 

ora sto lavorando con il database insolito come c'è una ragione al di là del mio controllo per le persone a mancare dalla tabella persone, ma hanno un record in CompanyPositions. Voglio filtrare le Posizioni Aziendali con le Persone scomparse unendole alle tabelle.

return (from pos in CompanyPositions 
     join p in People on pos.PersonId equals p.PersonId 
     select pos).ToList(); 

Linq vede questo join come ridondante e lo rimuove dall'SQL generato.

SELECT 
[Extent1].[CompanyPositionId] AS [CompanyPositionId], 
[Extent1].[CompanyId] AS [CompanyId], 
.... 
FROM [dbo].[CompanyPositions] AS [Extent1] 

Tuttavia nel mio caso non è ridondante. Posso risolvere il problema in questo modo

// The min date check will always be true, here to force linq to perform the inner join 
var minDate = DateTimeExtensions.SqlMinSmallDate; 

return (from pos in CompanyPositions 
     join p in People on pos.PersonId equals p.PersonId 
     where p.UpdatedDate >= minDate 
     select pos).ToList(); 

Tuttavia, questo ora crea un inutile in cui la clausola nel mio SQL. Per quanto mi riguarda vorrei rimuoverlo. Qualche idea o l'attuale design del database mi lega le mani?

+1

Cosa stai usando? LINQ a SQL? LINQ alle entità? Qualcos'altro? – svick

+1

Il modello ha proprietà di navigazione? Se è così, potresti scrivere qualcosa come 'where pos.Person! = Null'. – svick

+0

Sto usando LinqToSql, ho provato 'dove pos.Person! = Null' e 'p.PersonId! = 0' e Linq li rimuove. Nel caso di 'p.PersonId! = 0' lo cambia in 'pos.PersonId! = 0' che mi impressiona anche se non è quello che sto cercando. – Magpie

risposta

2

Dal PersonId viene dichiarato NOT NULL (e suppongo che sia dichiarato come FK to People), allora non sono sicuro come potresti avere una CompanyPosition con una persona che non è stata assegnata; e Linq non può vedere come si può eiter, ed è per questo che, come avete osservato, Linq considera ridondante l'unione.

+1

Questo ha senso, il database con cui sto lavorando è una versione appiattita di un master molto più grande e complicato. Solo i dati relativi a un prodotto vengono inoltrati a questo e, ahimè, a causa di tali record mancanti non ci sono FK, questi sono applicati al master. In questo caso la persona è stata inedita, quindi non viene spinto dal master. Idealmente non sarebbe la CompanyPosition ma questo è fuori dal mio controllo. Sembra che il design db sia il problema principale qui. – Magpie

0

Se stai usando LinqToSql, è possibile utilizzare LoadWith simile a questo:

var context = new MyDataContext(); 
var options = new DataLoadOptions(); 
options.LoadWith<People>(x => x.CompanyPositions); 
context.LoadOptions = options; 
0

Non so come forzare linq per utilizzare un join. Ma la seguente dichiarazione dovrebbe darti il ​​risultato richiesto.

return (from pos in CompanyPositions 
     where (p in People select p.PersonId).Contains(pos.PersonId) 
     select pos).ToList(); 
0

clientside trasformazione:

(
from pos in CompanyPositions 
join p in People on pos.PersonId equals p.PersonId 
select new {pos, p} 
).ToList().Select(x => x.pos); 

Più filtraggio diretta:

from pos in CompanyPositions 
where pos.People.Any() 
select pos