Hibernate 按多对多关系查询时从结果列表中排除项目

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

我是Grails的一个新用户,我正在努力使用GORM设置进行一些更复杂的查询

我有两个域对象/表,LOCATION和REASON,它们具有多对多映射,由LOCATION\u REASON表管理:

Location.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
}
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引入了相关的子查询,目前还没有很好的文档记录,我很惊讶地看到与此问题相关的提交: