从数据库中获取具有连接实体的整个实体,并避免延迟加载,nHibernate QueryOver

时间:2012-05-08 12:19:56

标签: join fluent-nhibernate queryover

我有一个这样的实体:

public class Employment
{
    public virtual Company Company {get; set;}
    public virtual Person Person {get; set;}
    public virtual string Description {get; set;}
}

提供两个其他实体之间的关系。他们有相应的DTO,我想返回一个包含有关人员和公司的所有信息的结果集。查询是在Employment表上执行的,我的问题是Hibernate为每个公司和个人生成一个select语句。

在我的数据库中,Employment表有1000行。 Nhibernate生成2001年的选择陈述,一个用于就业清单,一个选择每个人和公司,因为我将它们映射到DTO。

我希望hibernate一次获取所有信息,在SQL中我会做这样的事情:

SELECT e.Description, c.A, c.B, c.C, p.D, p.E, p.F
FROM Employment e
JOIN Company c ON e.Company_Id = c.Company_Id
JOIN Person p ON e.Person_Id = p.Person_Id;

甚至

SELECT Description FROM Employment;

SELECT c.A, c.B, c.C FROM Employment e
JOIN Company c ON e.Company_Id = c.Company_Id;

SELECT p.D, p.E, p.F FROM Employment e
JOIN Person p ON e.Person_Id = p.Person_Id;

我是nHibernate,QueryOver的新用户。我也欢迎Linq-To-Entities的答案,但我更喜欢避免使用LINQ查询表达式。

我浏览了整个网络,阅读了JoinQuery,JoinAlias和Fetch,并且已经达到了类似的目标:

//This works, but the objects are retrieved as PersonProxy and CompanyProxy,
//generating 2 SELECT statements for each Employment I map to EmploymentDto
var queryOver =
    session.QueryOver<Employment>()
    .Fetch(x => x.Person).Eager
    .Fetch(x => x.Company).Eager
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());    


//This works, but the objects are still retrieved as PersonProxy and CompanyProxy,
var queryOver =
    session.QueryOver<Employment>()
        .JoinAlias(x => x.Person, () => personAlias, JoinType.InnerJoin)
        .JoinAlias(x => x.Company, () => companyAlias, JoinType.InnerJoin);
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());

JoinQuery也提供了相同的结果。我觉得我在这里缺少一些重要的东西。应该在查询中或在.List()之前完成某些操作以获取所有子实体,而不是加载包含许多装载了PersonProxy和CompanyProxy的Employment实体的列表。但是,我不知道如何......

编辑:添加了映射

数据库表:

TABLE Company(
Id,
A,
B,
C)

TABLE Person(
Id,
D,
E,
F);

TABLE Employment(
Person_Id,
Company_Id,
Description);

实体

public class Company
{
    public virtual string Id { get; set; }
    public virtual string A { get; set; }
    public virtual bool B { get; set; }
    public virtual bool C { get; set; }
}

public class Person
{
    public virtual string Id { get; set; }
    public virtual string D { get; set; }
    public virtual string E { get; set; }
    public virtual string F { get; set; }
}

public class Employment
{
    public virtual Person Person { get; set; }
    public virtual Company Company { get; set; }
    public virtual string Description { get; set; }

    public override bool Equals(object obj)
    {
        Employment toCompare = obj as Employment;
        if (toCompare == null)
            return false;
        return (this.GetHashCode() != toCompare.GetHashCode());
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int results = Person != null ? Person.GetHashCode() : 0;
            results = (results * 397) ^ (Company != null ? Company.GetHashCode() : 0);
            results = (results * 397) ^ (Description != null ? Description.GetHashCode() : 0);
            return results;
        }
    }
}

映射

public class CompanyMap : SyncableClassMap<Company>
{
    public CompanyMap()
    {
        Table("Company");
        Id(x => x.Id).Column("Id").GeneratedBy.Assigned();
        Map(x => x.A).Column("A");
        Map(x => x.B).Column("B").CustomType<YesNoType>();
        Map(x => x.C).Column("C").CustomType<YesNoType>();
    }
}

public class PersonMap : SyncableClassMap<Person>
{
    public PersonMap()
    {
        Table("Person");
        Id(x => x.Id).Column("Id").GeneratedBy.Assigned();
        Map(x => x.D).Column("D");
        Map(x => x.E).Column("E");
        Map(x => x.F).Column("F");
    }
}

public class EmploymentMap : ClassMap<Employment>
{
    public EmploymentMap()
    {
        Table("Employment");
        CompositeId()
            .KeyReference(x => x.Person, "Person_Id")
            .KeyReference(x => x.Company, "Company_Id");
        Map(x => x.Description, "Description");
    }
}

2 个答案:

答案 0 :(得分:4)

编辑后,我发现你有一个关键引用而不是正常的多对一。

不幸的是,这似乎是QueryOver / Criteria的限制,即使指定了Fetchmode,它也不会急于加载关键引用。然而,Linq to NH没有这个限制。将查询更改为

using NHibernate.Linq;

var results = session.Query<Employment>()
    .Fetch(x => x.Person)
    .Fetch(x => x.Company)
    .ToList();

答案 1 :(得分:0)

我遇到了你在这里描述的同样的问题。我将以您的最后一段代码片段为例,因为这是我使其工作的方式:

//This works, but the objects are still retrieved as PersonProxy and CompanyProxy,
var queryOver =
    session.QueryOver<Employment>()
        .JoinAlias(x => x.Person, () => personAlias, JoinType.InnerJoin)
        .JoinAlias(x => x.Company, () => companyAlias, JoinType.InnerJoin);
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());

首先,您不必指定JoinType.InnerJoin,因为这是默认的连接类型。和你一样,我也发现这些人和公司都是懒散地加载。

但是,如果您将连接类型更改为JoinType.LeftOuterJoin,您将看到所有内容都是热切加载的。至少那是我所经历的。因此,请尝试将代码更改为以下内容:

//This works, but the objects are still retrieved as PersonProxy and CompanyProxy,
var queryOver =
    session.QueryOver<Employment>()
        .JoinAlias(x => x.Person, () => personAlias, JoinType.LeftOuterJoin)
        .JoinAlias(x => x.Company, () => companyAlias, JoinType.LeftOuterJoin);
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());

我无法向你解释为什么就是这样,我刚刚发现这是为了解决自己的经历。如果你做左外连接有问题,你可以尝试在执行映射之前(或同时)在代码中进行相应的过滤。