0

我在两个表之间具有一对一的关系,并且我希望能够创建一个 LINQ 查询,该查询将返回子表中有内容的“父”表。问题是 NH 正在生成的查询正在检查父表的 ID 是否不为空(并且永远不会),而不是连接到子表。这与我使用延迟加载还是非延迟加载无关。我正在使用带有覆盖的自定义自动映射约定,但这是生成的 HBM XML:

抽象类的映射,作为父类的具体类

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="AbstractClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" table="ABSTRACT_CLASS">
    <id name="AbstractClassId" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="ABSTRACT_CLASS_ID" />
      <generator class="identity" />
    </id>
    <joined-subclass name="ConcreteClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" table="CONCRETE_CLASS">
      <key>
        <column name="ABSTRACT_CLASS_ID" />
      </key>
      <one-to-one cascade="none" class="AuxiliaryClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" name="AuxiliaryClass" property-ref="Foo" />
    </joined-subclass>
  </class>
</hibernate-mapping>

子表的映射

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="AuxiliaryClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" table="AUXILIARY_CLASS">
    <id name="AuxiliaryClassiD" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="AUXILIARY_CLASS_ID" />
      <generator class="identity" />
    </id>
    <many-to-one class="ConcreteClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" name="Foo">
      <column name="FOO_ABSTRACT_CLASS_ID" />
    </many-to-one>
  </class>
</hibernate-mapping>

类定义

public abstract class AbstractClass
{
    public virtual Int32? AbstractClassId { get; set; }
}

public class ConcreteClass : AbstractClass
{
    public virtual AuxiliaryClass AuxiliaryClass { get; set; }
}

public class AuxiliaryClass
{
    public virtual Int32? AuxiliaryClassId { get; set; }

    public virtual ConcreteClass Foo { get; set; }
}

不起作用的 LINQ 查询是:

nh.Query<ConcreteClass>().Where(cc => cc.AuxiliaryClass != null);

正在生成的查询是:

select
    concretecl0_.CONCRETE_CLASS_ID as CONCRETE1_0_
from
    CONCRETE_CLASS concretecl0_
inner join
    ABSTRACT_CLASS concretecl0_1_
on
    concretecl0_.ABSTRACT_CLASS_ID=concretecl0_1_.ABSTRACT_CLASS_ID
where
    concretecl0_.ABSTRACT_CLASS_ID is not null

如果我关闭延迟加载,则连接到辅助表,但仍将具体类的表的 ID 与 null 进行比较。

编辑

根据@Suhas 的建议:

尝试将您的 Linq 查询更改为 nh.Query(cc => cc.AuxiliaryClass.AuxiliaryClassId > 0); 假设 AuxiliaryClassId 是 int 类型

我确实做到了cc => cc.AuxiliaryClass.AuxiliaryClassId != null,这很有效,让我得到了这个查询:

select
    concretecl0_.ABSTRACT_CLASS_ID as concretecl0_1_0_
from
    CONCRETE_CLASS concretecl0_
inner join
    ABSTRACT_CLASS concretecl0_1_
on
    concretecl0_.concretecl0_=concretecl0_1_.concretecl0_
  , AUXILIARY_CLASS auxiliaryc1_
where
    concretecl0_.ABSTRACT_CLASS_ID=auxiliaryc1_.FOO_ABSTRACT_CLASS_ID
and (auxiliaryc1_.AUXILIARY_CLASS_ID is not null)

但是,当我尝试相反的情况时cc => cc.AuxiliaryClass.AuxiliaryClassId == null,我得到了一个无效的查询:

select
    concretecl0_.ABSTRACT_CLASS_ID as concretecl0_1_0_
from
    CONCRETE_CLASS concretecl0_
inner join
    ABSTRACT_CLASS concretecl0_1_
on
    concretecl0_.concretecl0_=concretecl0_1_.concretecl0_
  , AUXILIARY_CLASS auxiliaryc1_
where
    concretecl0_.ABSTRACT_CLASS_ID=auxiliaryc1_.FOO_ABSTRACT_CLASS_ID
and (auxiliaryc1_.AUXILIARY_CLASS_ID is null)
4

1 回答 1

0

只是从原始问题中列出我的评论(略微针对答案),因为这些似乎对问题的作者有所帮助

  1. 尝试将您的 Linq 查询更改为nh.Query<ConcreteClass>(cc => cc.AuxiliaryClass.AuxiliaryClassId > 0);假设AuxiliaryClassId是类型int
  2. 当您想要获取存在于ConcreteClass但不存在于AuxiliaryClass. 为此,您可能需要使用左外连接。如果您确实进行了左外连接,那么您可以通过 QueryOver(或 Linq 以一种不那么直接的方式)进行操作,然后检查代码中的无效性。根据您加载的数据集的大小,这在生产中可能不是一件好事。我不确定如何做子查询来实现你想要实现的目标
  3. 如果 LINQ 是唯一的选择,那么您可以使用DefaultIfEmpty方法在 LINQ 中获取左外连接。这个SO question应该是一个很好的起点。
  4. 最后,在这种情况下,一个普通的 SQL 可能是最有效的。如果您想沿着这条路线走,那么您可以ISession.CreateSQLQuery按原样使用和使用您的 SQL 查询
于 2015-08-24T21:27:46.330 回答