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

Join 从数据库中获取具有连接实体的整个实体并避免延迟加载,nHibernate QueryOver,join,fluent-nhibernate,queryover,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;} } SELECT e.Description, c.A, c.B, c.C, p.D, p.E, p.F FROM Employment e

我有这样一个实体:

public class Employment
{
    public virtual Company Company {get; set;}
    public virtual Person Person {get; set;}
    public virtual string Description {get; set;}
}
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;
//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());
提供其他两个实体之间的关系。他们有相应的DTO,我想返回一个结果集,其中包含个人和公司的所有信息。查询是在Employment表上执行的,我的问题是Hibernate为每个公司和每个人生成一条select语句

在我的数据库中,就业表有1000行。Nhibernate生成2001 select语句,当我将它们映射到DTO时,一个用于就业列表,另一个用于每个人和公司

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

public class Employment
{
    public virtual Company Company {get; set;}
    public virtual Person Person {get; set;}
    public virtual string Description {get; set;}
}
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;
//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());
甚至

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访问实体答案,但我更喜欢避免使用Linq查询表达式

我已经浏览了整个网络,阅读了JoinQuery、JoinAlias和Fetch的相关内容,并得出如下结论:

public class Employment
{
    public virtual Company Company {get; set;}
    public virtual Person Person {get; set;}
    public virtual string Description {get; set;}
}
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;
//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());
实体

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");
    }
}
公共类公司映射:SyncableClassMap
{
上市公司地图()
{
表(“公司”);
Id(x=>x.Id).Column(“Id”).GeneratedBy.Assigned();
映射(x=>x.A)。列(“A”);
Map(x=>x.B).Column(“B”).CustomType();
Map(x=>x.C).Column(“C”).CustomType();
}
}
公共类PersonMap:SyncableClassMap
{
公众人物地图()
{
表(“人”);
Id(x=>x.Id).Column(“Id”).GeneratedBy.Assigned();
映射(x=>x.D)。列(“D”);
映射(x=>x.E)。列(“E”);
映射(x=>x.F)。列(“F”);
}
}
公共类EmploymentMap:ClassMap
{
公共就业地图()
{
表(“就业”);
复合ID()
.KeyReference(x=>x.Person,“Person\u Id”)
.KeyReference(x=>x.Company,“Company_Id”);
地图(x=>x.描述,“描述”);
}
}

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

//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());

我无法向你解释为什么会这样,我只是根据自己的经验发现了这一点。如果执行左外部联接有问题,可以在执行映射之前(或同时)尝试在代码中进行相应的筛选。

编辑后,我看到您有一个键引用,而不是正常的多对一

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

using NHibernate.Linq;

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

session.QueryOver().Fetch(x=>x.Person)。Eager.Fetch(x=>x.Company)。Eager
应该在不生成代理的情况下进行Eager Fetch。你确定你不过滤个人和公司吗?是的,我确定。然而,我和我们的系统架构师聊过,我们很可能会禁用懒散加载,所以在我们做出决定之前,我没有做过更多的研究。你能发布映射吗?我无法在示例应用程序中复制。我将尝试升级到最新版本的nHibernate,如果我仍然存在此问题,可以使用映射发回注释。升级不起作用。还是一样的问题。添加了映射到OPS,谢谢,但我仍然有同样的问题。越来越确信某个地方有bug。我和你做的完全一样,个人和公司的推荐信仍然是懒洋洋的。请注意,从NH生成的SQL如何缺少JOIN语句:NHibernate:选择this.Person\u Id作为Person1\u 72\u 0,this.Company\u Id作为Companyt2\u 72\u 0,this.Description作为Description作为Description 72\u 0这是刚升级的,仍然是相同的问题。我测试了你的答案,不幸的是它对我不起作用。