2012-02-15 11 views
5

mam następujące dwie tabele:NHibernate - Left dołącza

Praca Areaid, JobNo (klucz kompozytowe)

Dzienniki LogID, Areaid, JobNo

trzeba uzyskać wszystkie oferty pracy: które nie mają powiązanych z nimi dzienników. W SQL mogłem zrobić:

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 

Ale nie jestem pewien, jak to osiągnąć z NHibernate. Czy ktokolwiek może zaoferować jakieś wskazówki?

Oto moje mapowania:

<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> 

Dzięki

Aktualizuj

OK, zmodyfikowana odpowiedź nieznacznie Nosila, a to jest teraz robi to, co chciałem:

Log logs = null; 

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

Musiałem również dodać to do mojego zadania mapowanie:

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

Dzięki za pomoc. :)

+0

Czy możesz opublikować zapytanie, które już masz? – Nosila

+0

Powyższe zapytanie SQL jest aktualnie tym, czego używam. Właśnie uczę się NH i próbuję przekonwertować małą aplikację na jej używanie. – Tom

+0

Czy masz utworzone mapowania? Poza tym, ktoś mnie koryguje, jeśli się mylę, ale myślę, że potrzebujesz NHibernate 3.2, aby dodać warunki do swojego join (w każdym razie używając API 'QueryOver'). – Nosila

Odpowiedz

6

Nie znam się na identyfikatorach złożonych, ponieważ ich nie używam, więc wiem, że NHibernate automatycznie utworzy właściwe lewe połączenie. Niemniej jednak poniższe (nie testowane) zapytanie powinno zacząć od Ciebie.

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; } 
} 

Uwaga: Do ustawienia warunków łączenia potrzebny jest NHibernate 3.2.

+1

Dzięki. Muszę się nad tym zastanowić (jest w tym kilka błędów). Wydaje się to również niezwykle skomplikowane w przypadku tak prostej kwerendy. – Tom

+0

@Tom Zgadzam się ze złożonością, pisanie tego w SQL byłoby znacznie prostsze. Czuję, że abstrakcja ORM wymyka się spod kontroli. – Jafin

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

Aktualizacja: widziałem, że dodałeś mapowanie. Powyższy kod działa tylko dla następującego mapowania:

+0

Nice. Lubię to rozwiązanie lepiej. – Nosila

+0

To wydaje się łatwiejsze, chociaż pojawia się błąd "Nie można użyć podzapytań na kryterium bez projekcji". Co więcej, czy będzie to droższe zapytanie, ponieważ używa podokresów zamiast zwykłego lewego łączenia? – Tom

+0

1) dodano projekcję. 2) nie sądzę, że jest droższe, ponieważ robi to samo. możesz sprawdzić plan zapytania – Firo