我有一个这样的实体:
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");
}
}
答案 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());
我无法向你解释为什么就是这样,我刚刚发现这是为了解决自己的经历。如果你做左外连接有问题,你可以尝试在执行映射之前(或同时)在代码中进行相应的过滤。