【问题标题】:How to match all children using hql如何使用 hql 匹配所有孩子
【发布时间】:2010-11-24 23:04:39
【问题描述】:

选择具有子集合的父实体(不同)列表的最佳/首选方法是什么,该子集合包含子参数列表中所有条目的匹配项?

我正在执行我的搜索的“任何”版本,如下所示:

select p.Id, p.Name from parent p 
where exists(from p.Children c where c in (:childList))

但是,我对如何最好地执行此搜索的“全部”版本感到有些困惑。目前,我正在为我感兴趣的每个孩子动态创建 hql;像这样:

select p.Id, p.Name from parent p 
where :child1 in elements(p.Children)
and   :child2 in elements(p.Children)
-- etc...

我不禁想到有更好的方法来做到这一点;谁能指出我正确的方向?

作为参考,我使用的是 NHibernate 2.1.2

【问题讨论】:

标签: nhibernate hibernate hql


【解决方案1】:

有趣的问题,我没有找到一个简单的答案。使用“(:childList) 中的所有元素(p.Children)”的简单尝试无法生成有效的 SQL。这个怪物最终工作了......

var query = session.CreateQuery("select p from Parent p join p.Children c where c in (:childList) group by p.Id, p.Name having count(p) = :childListSize");
var children = new[] {session.Load<Child>(1),session.Load<Child>(2),session.Load<Child>(3)};
query.SetParameterList("childList", children);
query.SetParameter("childListSize", children.Length);

让我们分解 HQL...

select p from Parent p 
join p.Children c 
where c in (:childList) 
group by p.Id, p.Name 
having count(p) = :childListSize

我们正在创建一个包含子节点的内连接,它产生多行,选择子列表中子节点所在的那些行,按父节点分组,并查看我们是否获得了预期的行数并仅返回那些父节点。呼!

请注意,您必须明确指定 group by 中的所有属性。否则 NH 仅包含 Id 和 group by 失败。

顺便说一句 - 我在 NH3 上运行了这个,但我想不出任何原因它不适用于 NH2.1.2。

【讨论】:

  • 有趣的方法 - 我会试一试,看看性能数据是什么样的。顺便说一句,在 group by 中指定属性并不是什么大问题,因为我已经在 select 语句中这样做了(返回一个 dto 而不是一个完整的实体)
  • 这对于我的测试用例来说似乎运行得非常有效;虽然它让你想知道为什么没有某种“全在”结构让 hql/sql 涵盖这种情况:)
  • 这会很方便,不是吗?当我开始深入研究时,我很惊讶 SQL 不支持“(list1) in (list2)”之类的东西。我认为我的技术足够通用,可以添加到 HQL 中。 NHibernate 团队总是愿意接受补丁。 :)
  • 詹姆斯,我会质疑它可能有多“一般”......可能会因分组条款而变得相当复杂;更不用说必须在飞行中确定孩子的数量..尽管如此:)我希望 Diego 能在这个上投入 0.02 美元。
【解决方案2】:

只要关联存在,您就可以查询子级并选择父级,类似这样...

select distinct c.Parent.Id, c.Parent.Name from Child c 
where c in (:childList))

【讨论】:

  • 这对于我的某些情况当然是一种选择,但并非我的所有实体都具有双向关系 - 所以这种方法不适用于那些。
  • 让我感到奇怪的是有一个域/映射集合被映射,而相应的多对一属性却没有。
  • 捷豹;这种方法也有一个轻微的缺点,因为我试图使用一个通用模板来概括几个搜索;使用此方法,每次搜索我的选择语句都会有所不同,使用 James 方法,这不是问题。
  • @Jaguar - 在我的模型中,父母和孩子之间存在单向关系是很常见的。如果对象模型只需要一个方向的遍历,我只包括那个。
  • 也许我遗漏了一些东西,但这个查询不会让所有有孩子的父母都知道。取 P1->C1 和 P2->C1,C2。如果您查询所有同时拥有 C1 和 C2 的父母,您将同时获得 P1 和 P2。您仍然需要某种 group by/having 子句来消除仅具有请求子集的父级。
【解决方案3】:

只要运用一些逻辑,我们就能找到答案, 首先,您在这个查询中得到了答案:

select p.Id, p.Name from parent p 
where exists(from p.Children c where c in (:childList))

这里的问题是,我们在这里搜索“childList”列表中存在至少一个孩子的父母,但是我们需要一个所有孩子都是的父母在 childList 中.. 但我们也知道 没有 至少 childList 中不存在的孩子的父母是同一件事。所以:

select p.Id, p.Name from parent p 
where not exists(from p.Children c where c not in (:childList))

可选地,我们有 没有孩子的父母有时根据情况是另一个问题,所以:

select p.Id, p.Name from parent p 
where exists elements(p.Children) and not exists(from p.Children c where c not in (:childList))

【讨论】:

    猜你喜欢
    • 2014-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多