Nhibernate 基于HQL的多对多关系次优查询

Nhibernate 基于HQL的多对多关系次优查询,nhibernate,many-to-many,hql,Nhibernate,Many To Many,Hql,我有两个实体,位置和行业,它们之间有一个链接表。我已经在两个实体之间的两个方向上配置了多对多关系 在搜索查询中,我试图选择与行业列表关联的位置 在几天又几天试图对CriteriaAPI进行争论之后,我决定转而使用HQL并放弃CriteriaAPI。但即使这样,对我来说也不太好——看起来,不管我是手工编写这个HQL查询,还是让CriteriaAPI来做,我最终得到的结果都是一样的 我通过以下两种方式获得了正确的结果: var q = Data.Query("select distinct loc

我有两个实体,位置和行业,它们之间有一个链接表。我已经在两个实体之间的两个方向上配置了多对多关系

在搜索查询中,我试图选择与行业列表关联的位置

在几天又几天试图对CriteriaAPI进行争论之后,我决定转而使用HQL并放弃CriteriaAPI。但即使这样,对我来说也不太好——看起来,不管我是手工编写这个HQL查询,还是让CriteriaAPI来做,我最终得到的结果都是一样的

我通过以下两种方式获得了正确的结果:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind in (:ind)");

q.SetParameterList("ind", new Industry[] { Data.GetIndustry(4), Data.GetIndustry(5) });
public class Industry {
    //Other stuff
    public virtual List<LocationIndustry> LocationIndustries {get; set:;}
}

public class LocationIndustry {
    public virtual Location Location {get; set;}
    public virtual Industry Industry {get; set;}
}

public class Location {
    //normal stuff
    public virtual IList<LocationIndustry> LocationIndustries {get; set;}
}
而且(更好)是这样的:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind.id in (:ind)");

q.SetParameterList("ind", new int[] { 4, 5 });
不幸的是,两者都会导致次优查询:

select distinct
  location0_.Id as Id16_,
  location0_.Name as Name16_,
  (etc.)
from Location location0_
  inner join LocationIndustry industries1_
    on location0_.Id=industries1_.LocationId
  inner join Industry industry2_
    on industries1_.IndustryId=industry2_.Id
where
  industry2_.Id in (? , ?)
为什么要额外加入

NH是否聪明到知道Industry.Id属性(作为查询中唯一涉及的行业属性)存储在LocationIndustry链接表中,并且不需要额外连接到行业表本身

还是我做错了什么

理想情况下,对我来说最直观的事情是写:

from Location loc where loc.Industries in (:ind)
这不起作用-它抛出了一个错误,并表示它不了解Industries属性。我猜是因为行业在编程术语中是一个“属性”,在DBMS术语中实际上是一个“关系”

在HQL中编写此查询最简单、最有效的方法是什么


谢谢

考虑到您使用的映射策略,我不确定您是否可以避免这种额外的连接

您可以通过使用中间类来避免这种情况,但这意味着您需要这样的类结构:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind in (:ind)");

q.SetParameterList("ind", new Industry[] { Data.GetIndustry(4), Data.GetIndustry(5) });
public class Industry {
    //Other stuff
    public virtual List<LocationIndustry> LocationIndustries {get; set:;}
}

public class LocationIndustry {
    public virtual Location Location {get; set;}
    public virtual Industry Industry {get; set;}
}

public class Location {
    //normal stuff
    public virtual IList<LocationIndustry> LocationIndustries {get; set;}
}
公共级行业{
//其他东西
公共虚拟列表位置{get;set:;}
}
公共类定位行业{
公共虚拟位置{get;set;}
公共虚拟产业产业{get;set;}
}
公共类位置{
//普通的东西
公共虚拟IList LocationIndustries{get;set;}
}

然后您可以查询
LocationIndustry
类,避免加入
Location

有趣的问题。但是,您是否测量了有无额外连接的查询之间的显著差异?也许它做了额外的连接来处理连接表中没有外键约束和一些记录引用不存在的行业的情况?这是一种可能的解释,虽然这似乎是一个糟糕的解决办法,以解释不一致的数据,不应该出现在一个精心设计和适当维护的数据库开始。似乎更可能这只是一个尚未实现的优化?+1,谢谢,但我已经考虑过这个选项,我觉得它很难看-我不想扭曲域模型,引入无用的实体;这还意味着,在添加/删除关联时,我必须管理更多的对象,并维护两倍的关系。(我开始认为,即使像NH这样的怪物也无法处理阻抗失配的所有方面……)事实上,这是一种以性能换取灵活性的情况。在这种情况下,您可以使用SQLQuery或命名查询吗?您可以用SQL编写查询,但仍然可以将其映射到对象。如果使用nh3.1,您可以在hql上使用新的
语法将in子句添加到联接中。然而,当涉及到在多对多关系中使用它时,这是有问题的。谢谢你的所有建议-我会接受你的回答,因为在NH中显然没有更好的方法来做到这一点。就我个人而言,我已经决定使用额外的连接,除非有必要对其进行优化,否则我不想让软件复杂化以适应ORM。