我试图在没有单个根实体的情况下获取多个实体(实体关系的有向图只是弱连接图,没有强连接)我无法弄清楚如何做它在Nhibernates QueryOver api(或Linq,但似乎更弱)
这些是我的关系:
ClientTaxEntity
引用了1 Client
和N Manufacturers
InstructionTemplate
引用了1 Client
和1 Manufacturer
我希望获得所有可能的客户端 - 制造商对的结果(可能=它们在ClientTaxEntity中一起)并获取模板(如果存在)(否则为null)
这是我到目前为止所尝试的:
Client client = null;
Manufacturer manufacturer = null;
InstructionTemplate template = null;
ClientTaxEntity taxEntity = null;
InstructionTemplateInfo info = null;
var query =Session.QueryOver<ClientTaxEntity>(() => taxEntity)
.JoinAlias(x => x.Client, () => client)
.JoinAlias(x => x.Manufacturers, () => manufacturer)
.Left
.JoinQueryOver(() => template, () => template,() => template.Client == client && template.Manufacturer == manufacturer);
var result = query
.SelectList(builder => builder
.Select(() => client.Name).WithAlias(() => info.ClientName)
.Select(() => client.Id).WithAlias(() => info.ClientId)
.Select(() => manufacturer.Name).WithAlias(() => info.ManufacturerName)
.Select(() => manufacturer.Id).WithAlias(() => info.ManufacturerId)
.Select(() => template.Id).WithAlias(() => info.TemplateId)
.Select(() => template.Type).WithAlias(() => info.Type)
)
.TransformUsing(Transformers.DistinctRootEntity)
.TransformUsing(Transformers.AliasToBean<InstructionTemplateInfo>())
.List<InstructionTemplateInfo>();
info对象是我想要的结果。
但是语法.JoinQueryOver(() => template
似乎对路径参数无效(例外情况说:could not resolve property: template of: ClientTaxEntity
答案 0 :(得分:1)
要在SQL中编写查询时获得所需的结果,有必要写下以下内容:
SELECT Client_Id, Client_Name, Manufacturer_Id, Manufacturer_Name
FROM
(
SELECT Client.Id as Client_Id, Client.Name as Client_Name,
Manufacturer.Id as Manufacturer_Id, Manufacturer.Name as Manufacturer_Name
FROM ClientTax
INNER JOIN Client on Client.Id = ClientTax.Client_Id
INNER JOIN Manufacturer on Manufacturer.Id = Manufacturer.Manufacturer_id
UNION
SELECT Client.Id, Client.Name, Manufacturer.Id, Manufacturer.Name
FROM InstructionTemplate
INNER JOIN Client on Client.Id = InstructionTemplate.Client_Id
INNER JOIN Manufacturer on Manufacturer.Id = InstructionTemplate.Manufacturer_id
) a
GROUP BY Client_Id, Client_Name, Manufacturer_Id, Manufacturer_Name;
不幸的是,将这样的查询转换为NHibernate的查询API之一是不可能的,因为NHibernate不支持UNION语句*。在NHibernate的错误跟踪器中查看此question和功能请求NH-2710。
*使用union-subclass
时除外。有关详细信息,请参阅docs
我能看到的唯一选择是
执行SQL查询并将其映射到DTO
public class InstructionTemplateInfo
{
public int Client_Id { get; set; }
public string Client_Name { get; set; }
public int Manufacturer_Id { get; set; }
public string Manufacturer_Name { get; set; }
}
然后
var result = session
.CreateSQLQuery(theSQLQueryString)
.SetResultTransformer(Transformers.AliasToBean<InstructionTemplateInfo>())
.List<InstructionTemplateInfo>();
在数据库中创建一个视图,并将其映射为普通实体。
如果DBMS支持多个结果集,例如SQL Server,您可以编写两个查询,但将它们标记为Future
,然后在代码中合并两个结果集,即
var resultSet1 = Session.QueryOver<ClientTaxEntity>(() => taxEntity)
.JoinAlias(x => x.Client, () => client)
.JoinAlias(x => x.Manufacturers, () => manufacturer)
.SelectList(builder => builder
.SelectGroup((() => client.Name).WithAlias(() => info.ClientName)
.SelectGroup((() => client.Id).WithAlias(() => info.ClientId)
.SelectGroup((() => manufacturer.Name).WithAlias(() => info.ManufacturerName)
.SelectGroup((() => manufacturer.Id).WithAlias(() => info.ManufacturerId)
.TransformUsing(Transformers.AliasToBean<InstructionTemplateInfo>())
.Future<InstructionTemplateInfo>;
var resultSet2 = Session.QueryOver<InstructionTemplate>(() => taxEntity)
.JoinAlias(x => x.Client, () => client)
.JoinAlias(x => x.Manufacturers, () => manufacturer)
.SelectList(builder => builder
.SelectGroup((() => client.Name).WithAlias(() => info.ClientName)
.SelectGroup((() => client.Id).WithAlias(() => info.ClientId)
.SelectGroup((() => manufacturer.Name).WithAlias(() => info.ManufacturerName)
.SelectGroup((() => manufacturer.Id).WithAlias(() => info.ManufacturerId)
.TransformUsing(Transformers.AliasToBean<InstructionTemplateInfo>())
.Future<InstructionTemplateInfo>;
var result = resultSet1.Concat(resultSet2 )
.GroupBy(x=>x.ClientId+"|"+x.ManufacturerId)
.Select(x=>x.First());
这种方法的优点是DBMS只会被击中一次。 有关此功能的详细信息,请参阅Ayende's blog post。