2

我试图在没有单个根实体的情况下获取多个实体(实体关系的有向图只是一个弱连接图,而不是强连接图),我无法弄清楚如何在 Nhibernates QueryOver api(或 Linq,但是这似乎更弱)

这些是我的关系:

ClientTaxEntity参考文献 1Client和 NManufacturers

InstructionTemplate参考文献 1Client和 1Manufacturer

我想获得所有可能的客户-制造商对的结果(可能 = 它们在 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

4

1 回答 1

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 的错误跟踪器中的这个问题和功能请求NH-2710

*使用时除外union-subclass。有关更多详细信息,请参阅文档

我能看到的唯一选择是

  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 的博客文章

于 2013-04-20T09:37:48.540 回答