NHibernate QueryOver - 无路径连接(或“反向”路径)

时间:2013-04-19 09:43:41

标签: nhibernate queryover nhibernate-criteria

我试图在没有单个根实体的情况下获取多个实体(实体关系的有向图只是弱连接图,没有强连接)我无法弄清楚如何做它在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

1 个答案:

答案 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

我能看到的唯一选择是

  1. 执行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>();
    
  2. 在数据库中创建一个视图,并将其映射为普通实体。

  3. 如果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