2012-02-15 43 views
5

我有以下两个表:NHibernate的 - 左加入

乔布斯 areaID表示,JobNo(复合键)

日志 LOGID,areaID表示,JobNo

我需要得到所有作业没有任何与他们关联的日志。在SQL我可以这样做:

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 

但我不知道如何使用NHibernate完成此操作。任何人都可以提供任何指针?

这里是我的映射:

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

感谢

更新

OK,我修改Nosila的轻微的答案,这是现在在做什么,我想:

Log logs = null; 

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

我也不得不将这添加到我的工作中映射:

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

感谢您的帮助。 :)

+0

你可以发布你现在查询? – Nosila 2012-02-15 12:40:12

+0

上面的SQL查询是我正在使用的。我现在刚学习NH,并试图将小应用程序转换为使用它。 – Tom 2012-02-15 12:48:20

+0

你有你的映射创建?另外,有人纠正我,如果我错了,但我认为你需要NHibernate 3.2为你的连接添加条件(无论如何使用'QueryOver' API)。 – Nosila 2012-02-15 12:52:14

回答

6

我不熟悉组合标识符,因为我不使用它们,所以我知道NHibernate会自动创建正确的左连接。无论如何,下面的(未测试)查询应该让你开始。

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

注意:您需要NHibernate 3.2来设置连接条件。

+1

谢谢。我必须仔细考虑这一点(其中有一些错误)。对于这样一个简单的查询,它似乎也非常复杂。 – Tom 2012-02-15 13:25:15

+0

@Tom我同意这种复杂性,在SQL中编写它会简单得多。我觉得ORM抽象正在失控。 – Jafin 2012-08-09 04:16:37

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

更新:我看到你添加了映射。上面的代码只适用于以下映射

<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

不错。我更喜欢这个解决方案。 – Nosila 2012-02-15 13:08:07

+0

这似乎更容易,虽然我得到错误“不能使用没有投影的条件上的子查询”。此外,这是一个更昂贵的查询,因为它使用子查询而不是简单的左连接? – Tom 2012-02-15 13:24:30

+0

1)增加投影。 2)我不认为它做同样的事情会更昂贵。您可以查看查询计划 – Firo 2012-02-16 05:54:39