【问题标题】:NHibernate QueryOver - Join without path (or with "reversed" path)NHibernate QueryOver - 无路径加入(或“反向”路径)
【发布时间】:2013-04-19 09:43:40
【问题描述】:

我试图在没有单个根实体的情况下获取多个实体(实体关系的有向图只是一个弱连接图,不是强连接),我不知道该怎么做它在 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(() =&gt; template 似乎对路径参数无效(异常表示:could not resolve property: template of: ClientTaxEntity

【问题讨论】:

  • 我知道我可以在两个查询中做到这一点,因为我有两个根实体,但我正在寻找一个单一的数据库查询解决方案。
  • ClientTaxEntityInstructionTemplate之间有关系吗?
  • 不,没有。我也尝试用子选择替换连接,但如果子选​​择的结果产生超过 1 个值,它会失败

标签: nhibernate queryover nhibernate-criteria


【解决方案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 不支持 UNION 语句*,因此无法将此类查询转换为 NHibernate 的查询 API 之一。在 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

【讨论】:

  • 我采用了未来的方法,这正是我所需要的。谢谢
  • 很遗憾 NHibernate 不支持联合,但看起来需要进行大量更改才能使其正常工作。幸运的是,由于 NHibernate 非常灵活,几乎总是有不止一种方法可以解决问题。
猜你喜欢
  • 2020-10-04
  • 2016-03-18
  • 2012-05-25
  • 1970-01-01
  • 2018-07-22
  • 2017-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多