Hibernate 按多对多关系查询时从结果列表中排除项目
我是Grails的一个新用户,我正在努力使用GORM设置进行一些更复杂的查询 我有两个域对象/表,LOCATION和REASON,它们具有多对多映射,由LOCATION\u REASON表管理: Location.groovy:Hibernate 按多对多关系查询时从结果列表中排除项目,hibernate,grails,many-to-many,subquery,gorm,Hibernate,Grails,Many To Many,Subquery,Gorm,我是Grails的一个新用户,我正在努力使用GORM设置进行一些更复杂的查询 我有两个域对象/表,LOCATION和REASON,它们具有多对多映射,由LOCATION\u REASON表管理: Location.groovy: class Location { String description // other fields static hasMany = [reasons: Reason] static mapping = { sor
class Location {
String description
// other fields
static hasMany = [reasons: Reason]
static mapping = {
sort description:"asc"
id generator:'native', params:[sequence:'ATTENDANCE_TRACKER.ID_SEQ']
reasons joinTable: [name: 'LOCATION_REASON', key: 'LOCATION_ID', column: 'REASON_ID'], cascade: 'none'
}
static namedQueries = {
findAllWhereReasonIsNot { reasonId ->
reasons { ne('id', reasonId) }
}
}
//Other stuff
}
class Reason {
String description
//other fields
static hasMany = [locations: Location]
static mapping = {
id generator:'native', params:[sequence:'ATTENDANCE_TRACKER.ID_SEQ']
locations joinTable: [name: 'LOCATION_REASON', key: 'REASON_ID', column: 'LOCATION_ID'], cascade: 'none'
}
//Other stuff
}
Reason.groovy:
class Location {
String description
// other fields
static hasMany = [reasons: Reason]
static mapping = {
sort description:"asc"
id generator:'native', params:[sequence:'ATTENDANCE_TRACKER.ID_SEQ']
reasons joinTable: [name: 'LOCATION_REASON', key: 'LOCATION_ID', column: 'REASON_ID'], cascade: 'none'
}
static namedQueries = {
findAllWhereReasonIsNot { reasonId ->
reasons { ne('id', reasonId) }
}
}
//Other stuff
}
class Reason {
String description
//other fields
static hasMany = [locations: Location]
static mapping = {
id generator:'native', params:[sequence:'ATTENDANCE_TRACKER.ID_SEQ']
locations joinTable: [name: 'LOCATION_REASON', key: 'REASON_ID', column: 'LOCATION_ID'], cascade: 'none'
}
//Other stuff
}
命名查询“findAllWhereReasonIsNot”的功能与我希望的不一样。我需要一个查询来完成获取所有尚未与指定原因关联的位置
在SQL术语中,我希望:
select * from location where id not in(select location_id from location_reason where reason_id = :reasonId);
但是,当前实现所完成的工作看起来或多或少经过了编辑,只包含相关信息,并且在生成hibernate SQL后具有合理的“选择为”名称,如下图所示:
select * from
(
select
this_.id as loc_location_id,
this_.description as location_description,
reasons3_.LOCATION_ID as loc_reas_location_id,
reasons3_.REASON_ID as loc_reas_reason_id,
reasons_al1_.id as reas_reason_id,
reasons_al1_.description as reason_description
from location this_
inner join location_reason reasons3_ on this_.id=reasons3_.LOCATION_ID
inner join reason reasons_al1_ on reasons3_.REASON_ID=reasons_al1_.id
where (reasons_al1_.id <> :reasonId)
order by lower(this_.description) asc
);
这将导致每个位置的多个副本的列表,每个与之相关的原因一个。这将防止结果列表实际排除与原始reasonId关联的位置,因为其他原因与该位置关联
我对条件和HQL做了一些研究,但无法得到一个工作查询来生成。。。似乎标准和HQL有一些限制,所以我甚至不确定这是否可能。有人知道如何在命名查询中完成简单的“不在”子查询吗?For有许多关系,您需要创建别名: 例如:
Location.createCriteria().list(){
createAlias("reasons","r")
not{'in'("r.id", arrayList)}
}
这也适用于命名查询。经过多次尝试和错误,我得到了一个正常工作的HQL查询:
Location.findAll("from Location loc where loc not in (select l from Location l join l.reasons as r where r.id = ?) order by loc.description")
非常感谢cfrick为我指明了正确的方向。我以前曾简要地看过HQL,但误解了一些Grails文档,认为它只支持HQL的“where”子句。我还因为试图直接访问联接表而挂断了电话
以下是我学到的:
Grails通过find、findAll和executeQuery方法支持HQL。后者支持自定义结果集,而前两个则绑定到域实例
Groovy控制台非常棒。我以前不知道它的存在,但这是一种加快对编程查询进行故障排除的极好方法
HQL只适用于您的域类,但有一些时髦的语法,允许您访问联接表记录位置_REASON,在我的例子中:从位置l以r形式联接l.reasons,其中r.id=?
为了将域实例从位置或原因中分离出来,在我的示例中是从该连接记录中分离出来的,您需要选择表名或其别名:select l from Location l
您是否考虑过我假设查询将为我提供与原因id不相同的所有位置id。。。这不是我想要的。我没有使用别名,因为我真正关心的是连接表,而不是原因集合。如果别名可以用于非属性的联接表,那么这实际上可能会起作用。我必须试一试。HQL很好,但不太容易与其他标准链接。但是,如果您需要构建这样简单的查询,也可以。Grails 2.4引入了相关的子查询,目前还没有很好的文档记录,我很惊讶地看到与此问题相关的提交: