2012-02-15 17 views
5

Ho le seguenti due tabelle:NHibernate - Sinistra si unisce

Lavoro areaid, JobNo (chiave composita)

Logs LOGID, areaid, JobNo

ho bisogno di ottenere tutti i lavori a cui non sono associati registri. In SQL che potevo fare:

SELECT Jobs.AreaID, 
     Jobs.JobNo 
FROM Jobs 
     LEFT JOIN Logs 
      ON Jobs.AreaID = Logs.AreaID 
      AND Jobs.JobNo = Logs.JobNo 
WHERE Logs.LogID is null 

Ma io non sono sicuro di come ottenere questo risultato con NHibernate. Qualcuno potrebbe offrire qualche suggerimento?

Qui sono le mie mappature:

<class name="Job" table="Jobs"> 
    <composite-key name="Id"> 
     <key-property name="JobNo"/> 
     <key-many-to-one name="Area" class="Area" column="AreaID"/> 
    </composite-key> 
</class> 

<class name="Log" table="Logs"> 
    <id name="Id" column="LogID"> 
     <generator class="identity"/> 
    </id> 
    <property name="JobNo"/> 
    <many-to-one name="Area" class="Area" column="AreaID"/> 
</class> 

Grazie

Aggiornamento

OK, ho modificato la risposta di Nosila un po ', e questo ora sta facendo quello che volevo:

Log logs = null; 

return session.QueryOver<Job>() 
    .Left.JoinAlias(x => x.Logs,() => logs) 
    .Where(x => logs.Id == null) 
    .List<Job>(); 

Ho anche dovuto aggiungere questo al mio lavoro mapping:

<bag name="Logs"> 
    <key> 
     <column name="JobNo"></column> 
     <column name="DivisionID"></column> 
    </key> 
    <one-to-many class="Log"/> 
</bag> 

Grazie per l'aiuto. :)

+0

Puoi pubblicare la query che hai ora? – Nosila

+0

La query SQL precedente è attualmente ciò che sto utilizzando. Sto solo imparando l'NH al momento e sto provando a convertire una piccola applicazione a usarla. – Tom

+0

Hai creato i tuoi mapping? Inoltre, qualcuno mi correggerà se sbaglio, ma penso che tu abbia bisogno di NHibernate 3.2 per poter aggiungere condizioni al tuo join (usando comunque l'API 'QueryOver'). – Nosila

risposta

6

Non ho familiarità con gli identificatori compositi perché non li uso quindi per tutto quello che so NHibernate creerà automaticamente il join sinistro corretto. Tuttavia, la query (non testata) qui sotto dovrebbe iniziare.

Job jobAlias = null; 
Log logAlias = null; 
YourDto yourDto = null; 

session.QueryOver<Job>() 
    // Here is where we set what columns we want to project (e.g. select) 
    .SelectList(x => x 
     .Select(x => x.AreaID).WithAlias(() => jobAlias.AreaID) 
     .Select(x => x.JobNo).WithAlias(() => jobAlias.JobNo) 
    ) 
    .Left.JoinAlias(x => x.Logs,() => logAlias, x.JobNo == logAlias.JobNo) 
    .Where(() => logAlias.LogID == null) 
    // This is where NHibernate will transform what you have in your `SelectList()` to a list of objects 
    .TransformUsing(Transformers.AliasToBean<YourDto>()) 
    .List<YourDto>(); 

public class YourDto 
{ 
    public int AreaID { get; set; } 
    public int JobNo { get; set; } 
} 

Nota: è necessario NHibernate 3.2 per impostare le condizioni di unione.

+1

Grazie. Devo rimuginare su questo (ci sono alcuni errori in esso). Sembra anche estremamente complesso per una query così semplice. – Tom

+0

@ Tom sono d'accordo con la complessità, scrivere questo in SQL sarebbe molto più semplice. Sento che l'astrazione ORM sta sfuggendo di mano. – Jafin

4
Job job = null; 
var jobsWithoutLogs = session.QueryOver(() => job) 
    .WithSubquery.WhereNotExists(QueryOver.Of<Log>() 
     .Where(log => log.Job == job) 
     .Select(Projections.Id())) 
    .List() 

Update: ho visto è stato aggiunto il mapping. Il codice sopra funziona solo per la seguente mappatura

<class name="Log" table="Logs"> 
    <id name="Id" column="LogID"> 
     <generator class="identity"/> 
    </id> 
    <many-to-one name="Job" > 
     <column name="JobNo"/> 
     <column name="AreaID"/> 
    <many-to-one /> 
</class> 
+0

Bello. Mi piace questa soluzione meglio. – Nosila

+0

Sembra più semplice, anche se sto ricevendo l'errore "Impossibile utilizzare le sottoquery su un criterio senza una proiezione". Inoltre, questa sarà una query più costosa dal momento che sta usando sottoquery invece di un semplice join di sinistra? – Tom

+0

1) aggiunta proiezione. 2) non credo sia più costoso dal momento che sta facendo la stessa cosa. puoi controllare il piano di query – Firo