0

我编写的代码实际上可以完成它的工作,但它并不是非常理想。

在我的示例中,我有两个非常简单的表

在此处输入图像描述

获取人名和相关国家/地区名称(如果可用)的简单 SQL 查询如下所示

SELECT Person.Name AS Name, Country.CountryName AS Country FROM Person LEFT OUTER JOIN Country ON Country.CountryId = Person.CountryId

在此处输入图像描述

使用 NHibernate 获取数据的构造良好的对象看起来像这样

在此处输入图像描述

很简单,对。我的模型看起来像这样

namespace NHibernateLeftJoin.Models
{
    public class Country
    {
        public virtual int CountryId { get; set; }
        public virtual string CountryName { get; set; }
    }

    public class Person
    {
        public virtual int PersonId { get; set; }
        public virtual string Name { get; set; }
        public virtual int CountryId { get; set; }
        public virtual Country CountryObject { get; set; }
    }
}

和映射

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="NHibernateLeftJoin.Models.Country, NHibernateLeftJoin" lazy="true">
    <id name="CountryId">
      <generator class="native" />
    </id>
    <property name="CountryName" />
  </class>

  <class name="NHibernateLeftJoin.Models.Person, NHibernateLeftJoin" lazy="true">
    <id name="PersonId">
      <generator class="native" />
    </id>
    <property name="Name" />
    <property name="CountryId" />
    <many-to-one name="CountryObject" class="NHibernateLeftJoin.Models.Country" lazy="false"
                 column="CountryId" outer-join="true" unique="true" not-null="false" cascade="none" />
  </class>
</hibernate-mapping>

这种方法的问题是 NHibernate 获取一个“Person”行并为每一行调用“Contry”表,如果我们有数千行,那不是很好。似乎不可能以与我们使用 SQL 相同的简洁方式执行此操作,或者是我使用了完全错误的方法。

任何有兴趣的人都可以在这里找到 VS 项目https://dl.dropboxusercontent.com/u/6208162/NHibernateLeftJoin.zip

谢谢

== 编辑 ==

查询可能如下所示

private static IList<Person> GetPersons()
{
    using (var session = NHibernateHelper.OpenSession())
    {
        //using (var transaction = session.BeginTransaction()) {}
        IQuery query = session.CreateQuery("FROM Person");
        return query.List<Person>();
    }
}

生成的sql会是这样的

NHibernate: select person0_.PersonId as PersonId1_, person0_.Name as Name1_, person0_.CountryId as CountryId1_ from Person person0_

NHibernate: SELECT country0_.CountryId as CountryId0_0_, country0_.CountryName as CountryN2_0_0_ FROM Country country0_ WHERE country0_.CountryId=@p0;@p0 = 1 [Type: Int32 (0)]

NHibernate: SELECT country0_.CountryId as CountryId0_0_, country0_.CountryName as CountryN2_0_0_ FROM Country country0_ WHERE country0_.CountryId=@p0;@p0 = 2 [Type: Int32 (0)]

NHibernate: SELECT country0_.CountryId as CountryId0_0_, country0_.CountryName as CountryN2_0_0_ FROM Country country0_ WHERE country0_.CountryId=@p0;@p0 = 3 [Type: Int32 (0)]

这对我的数据来说是非常合乎逻辑的,第一个查询它获取所有人员,然后它使用三个不同的查询获取 CountryObject 的数据(映射到用户的三个唯一国家)。

谢谢

4

3 回答 3

1

首先,删除此属性...public virtual int CountryId { get; set; }您可以通过...访问 CountryId CountryObject.CountryId。我认为您正在寻找的是fetch="join"您的 ManyToOne。它告诉 NH,每次查询一个人时都要外连接到这个表。这将使 ManyToOne 不懒惰。

http://nhibernate.info/doc/nh/en/#mapping-declaration-manytoone

通常,我会避免此设置并使用 QueryOver 手动加入或急切获取任何 ManyToOnes。如果我正在使用单个实体,我将为 ManyToOnes 使用默认的延迟加载。

Session.QueryOver<Person>()
    .Fetch(x => x.CountryObject).Eager
    .List();
于 2013-08-20T18:15:14.890 回答
0

解决这个问题的一种方法是在编写查询时投影到一个类中。

执行此类操作的 linq 查询可能如下所示

var people = from p in _session.Query<Person>() 
select new 
{ 
     Name = p.Name, 
     Country = p.Country == null ? String.Empty : p.Country.Name;
}

此外,您不需要 Person 对象上的 CountryId。如果一个人与某个国家/地区相关联,您应该能够像这个 person.Country.Id 一样获取 countryId。

于 2013-08-20T18:26:07.450 回答
0

解决方案是在 CreateQuery 方法中实现连接,如下所示

IQuery query = session.CreateQuery("FROM Person AS P LEFT JOIN FETCH P.CountryObject");
return query.List<Person>();

并像这样为 Person 编写映射文件

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="NHibernateLeftJoin.Models.Person, NHibernateLeftJoin" lazy="true">
    <id name="PersonId">
      <generator class="native" />
    </id>
    <property name="Name" />
    <property name="CountryId" />
    <many-to-one name="CountryObject" class="NHibernateLeftJoin.Models.Country"
                 column="CountryId" not-found="ignore"
                 cascade="none" />
  </class>
</hibernate-mapping>

在我看来,我无法理解为什么在将参数 fetch="join" outer-join="true" 添加到映射文件中的多对一元素时不会自动编写此查询。

于 2013-08-25T12:25:24.427 回答