NHibernate 多重内连接选择

标签 nhibernate nhibernate-mapping nhibernate-criteria

我试图让 NHibernate 基于 3 个表的内部联接执行一个简单的查询:

var sessionCriteria = session.CreateCriteria<FoobarMaster>("M")
.CreateCriteria("Accounts", "A", NHibernate.SqlCommand.JoinType.InnerJoin)
.CreateCriteria("TrackingRecords", "T", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(Restrictions.Eq("T.PicNumber", "123456"));
var foobarMaster = sessionCriteria.UniqueResult<FoobarMaster>();

LINQ 中也有同样的事情:

from m in session.Query<FoobarMaster>()
from a in m.Accounts
from t in a.TrackingRecords
where t.PicNumber == "12345"
select m

我使用 QueryOvers 和 JoinAliases 也有同样的效果。对于所有人来说,我遇到了运行时异常:

"could not resolve property: TrackingNo of: Account".

这很奇怪,因为 TrackingNoTrackingRecord 属性而不是 Account 属性。它甚至以 T 为前缀 - TrackingRecord 的别名。

这是我的映射:

<class name="FoobarMaster" table="T_FOOBAR_MASTER">
 <id name="FoobarMasterId" column="FOOBAR_MASTER_ID" type="int">
   <generator class="identity"/></id>
 <bag name="Accounts" cascade="all" inverse="true">
   <key column="FOOBAR_MASTER_ID" />
   <one-to-many class="FoobarAccount" />
 </bag>
...

<class name="FoobarAccount" table="T_FOOBAR_ACCOUNT">
 <id name="FoobarAccountId" column="FOOBAR_ACCOUNT_ID" type="int">
   <generator class="identity"/></id>
 <many-to-one name="FoobarMaster" class="FoobarMaster" column="FOOBAR_MASTER_ID" />
 <property name="AccountId" column="ACCOUNT_ID" />
 <bag name="TrackingRecords" cascade="all" inverse="true">
   <key column="ACCOUNT_ID" />
   <one-to-many class="FoobarAccount" />
 </bag>
...

<class name="TrackingRecord" table="T_TRACKING">
 <id name="TrackingId" column="TRACKING_ID" type="int"><generator class="identity"/></id>
 <many-to-one name="FoobarAccount" class="FoobarAccount" column="ACCOUNT_ID" />
 <property name="PicNumber" column="PICNUMBER" type="AnsiString" length="25" />
 ...

以下是类/实体:

public class FoobarMaster
{
 public virtual int FoobarMasterId { get; set; }
 public virtual IList<FoobarAccount> Accounts { get; set; }
...

public class FoobarAccount
{
 public virtual int FoobarAccountId { get; set; }
 public virtual FoobarMaster FoobarMaster { get; set; }
 public virtual int AccountId { get; set; }
 public virtual IList<TrackingRecord> TrackingRecords { get; set; }
...

public class TrackingRecord
{
 public virtual long TrackingId { get; set; }
 public virtual FoobarAccount FoobarAccount { get; set; }
 public virtual string PicNumber { get; set; }
...

最佳答案

真正的问题

这里的答案基于最新更新的问题,清晰且易于修复!该映射包含错误的 one-to-many 设置。查看第一级列表:

<bag name="Accounts" cascade="all" inverse="true">
  <key column="FOOBAR_MASTER_ID" />
  <!-- here we can see the CORRECT reference -->
  <one-to-many class="FoobarAccount" />
</bag>

另一方面,第二个级别具有相同的目标,这是错误的:

<bag name="TrackingRecords" cascade="all" inverse="true">
  <key column="ACCOUNT_ID" />
  <!--  WRONG. In deed, the Account does NOT contain 'PicNumber' -->
  <one-to-many class="FoobarAccount" />
</bag>

答案:

更改 <one-to-many class="FoobarAccount" />
进入 <one-to-many class="TrackingRecord" />

正确的映射应该是这样的:

<bag name="TrackingRecords" cascade="all" inverse="true">
  <key column="ACCOUNT_ID" />
  <!--  now we won't recieve the Account does not contain 'PicNumber'  -->
  <one-to-many class="TrackingRecord" />
</bag>

From that moment, all the stuff will work properly, the query in the begining of the question is correct. No need for subqueries etc

...

原始提示 - 与之前可用的信息相关

如果你的对象/实体像这样链接起来,你正在尝试实现的目标将会起作用

  1. Master 有多个(或引用)帐户
  2. Account 有很多(或引用)TrackingRecords

但是根据您遇到的问题,您的映射似乎是

  1. Master 有多个(或引用)帐户
  2. Master 有很多(或引用)TrackingRecords

那么,就只能这样实现SQL了

select m.* from t_master m
inner join t_account a on m.master_id = a.master_id
//inner join t_tracking t on a.account_id = t.account_id
inner join t_tracking t on m.account_id = t.account_id // the m.account_id
where t.tracking_no = '123456'

查询应该是这样的:

// do some filter over A
var rootQuery = session.CreateCriteria<Master>("M")
                       .CreateCriteria("Accounts", "A", NHibernate.SqlCommand.JoinType.InnerJoin);

// working with the T here
rootQuery.CreateCriteria("TrackingRecords", "T", NHibernate.SqlCommand.JoinType.InnerJoin)
         .Add(Restrictions.Eq("T.TrackingNo", "123456"));

更新,反射(reflect)问题扩展:

此映射不适合在一起:

TrackingRecords 的关键列是 ACCOUNT_ID

<class name="Account" table="T_ACCOUNT"> 
...
<bag name="TrackingRecords" cascade="all" inverse="true">
  <key column="ACCOUNT_ID" />
...

虽然来自 TrackingRecord 的引用是通过 ACCOUNT_NUMBER 完成的

<class name="TrackingRecord" table="T_TRACKING">
...
<many-to-one name="Account" class="Account" column="ACCOUNT_NUMBER" />
...

关于NHibernate 多重内连接选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21253258/

相关文章:

ASP.NET MVC 图像上传存储位置(数据库与文件系统)

nhibernate - 如何在Fluent NHibernate中按 namespace 添加映射

c# - 我如何解决 NHibernate.MappingException

c# - Fluent Nhibernate 将 MySQL Time(6) 映射到 C# DateTime 的问题

c# - NHibernate.LazyInitializationException 异常

c# - 使用 Nhibernate.Mapping.Attributes 指定复合键

c# - 在简单类型的集合上创建条件

nhibernate - 如何在NHibernate中与null建立一对一的关系?

NHibernate - 使用 Criteria API 对整数列进行 LIKE 搜索的最简单方法?

debugging - Npgsql - 不支持指定的方法