問題は、この特定の例でGORMに内部結合ではなく左結合を生成させるにはどうすればよいですか。
テストベッド:
クラスA、B、Cが与えられた場合:
class A{
B someObject
}
class B{
C importantObject
}
class C{
boolean interestingFlag
}
次のようなAクラスのすべての要素をリストしたいと思います。
これまでに試したこと:
このアプローチは、BCがnullであるAの正しいリストを生成します(条件付き2がコメント化されています)OR BCinterestingFlag = falseであるAの正しいリスト(条件付き1がコメント化されているかどうかに関係なく)。両方の条件文はコメント解除され、ABCinterestingFlag = false(ABC = null条件は無視されます)である要素のリストのみを返します
// approach 1 (conditional 1 is ignored)
def result = A.withCriteria{
someObject{
or{
isNull('importantObject') // conditional 1, works well when conditional 2 is commented out
importantObject{
eq('interestingFlag', false) // conditional 2, works well alone, discards conditional 1 when both of them are uncommented
}
}
}
}
編集:コメントで要求されているように、私は休止状態で生成されたSQLを貼り付けています:
Hibernate: select this_.id as id1_2_, this_.version as version1_2_,
this_.some_object_id as some3_1_2_, someobject1_.id as id2_0_,
someobject1_.version as version2_0_, someobject1_.important_object_id as
important3_2_0_, importanto2_.id as id0_1_, importanto2_.version as version0_1_,
importanto2_.interesting_flag as interest3_0_1_ from a this_
inner join b someobject1_ on this_.some_object_id=someobject1_.id
inner join c importanto2_ on someobject1_.important_object_id=importanto2_.id
where ((someobject1_.important_object_id is null or (importanto2_.interesting_flag=?)))
いくつか変更を加えて(内部結合を左結合に変更し、interestingFlag = "false"パラメーターを指定して)、直接pgAdminクエリツールにコピーして貼り付けた場合、すべてが期待どおりに機能します(ABC = nullとABCimportantFlagの両方を取得します) = falseオブジェクト)
Hibernate: select this_.id as id1_2_, this_.version as version1_2_,
this_.some_object_id as some3_1_2_, someobject1_.id as id2_0_,
someobject1_.version as version2_0_, someobject1_.important_object_id as
important3_2_0_, importanto2_.id as id0_1_, importanto2_.version as version0_1_,
importanto2_.interesting_flag as interest3_0_1_ from a this_
left join b someobject1_ on this_.some_object_id=someobject1_.id
left join c importanto2_ on someobject1_.important_object_id=importanto2_.id
where ((someobject1_.important_object_id is null or (importanto2_.interesting_flag=false)))
テスト済みで動作するソリューション:
def result = A.withCriteria{
createAlias('someObject', 'so', CriteriaSpecification.LEFT_JOIN)
createAlias('so.importantObject', 'imp', CriteriaSpecification.LEFT_JOIN)
or {
isNull('so.importantObject')
eq('imp.interestingFlag', false)
}
}
コメントで提案されているソリューションの更新:
def result = A.withCriteria{
createAlias('someObject', 'so', JoinType.LEFT_OUTER_JOIN)
createAlias('so.importantObject', 'imp', JoinType.LEFT_OUTER_JOIN)
or {
isNull('so.importantObject')
eq('imp.interestingFlag', false)
}
}
これを行うには、左結合を使用します。これは動作するはずですが、私はそれをライブでテストしていません。
def result = A.withCriteria{
someObject {
createAlias("importantObject", "io", CriteriaSpecification.LEFT_JOIN)
or{
isNull('importantObject') // conditional 1
eq('io.interestingFlag', false) // conditional 2
}
}
}
Eidt:この投稿に基づく: http://grails.1312388.n4.nabble.com/CriteriaBuilder-DSL-Enhancements-td4644831.html これも機能するはずです:
def result = A.withCriteria{
someObject {
isNull('importantObject') // conditional 1
importantObject(JoinType.LEFT) {
eq('interestingFlag', false) // conditional 2
}
}
}
両方のソリューションで結果を投稿してください。
編集2:これは、まさにあなたが説明した状況であるクエリですが、例とは異なります。ここから始めて、showSqlを使用して生成されたSQLをデバッグし、左結合をいじる必要があります。
def result = A.withCriteria{
or {
isNull('someObject')
eq('someObject.importantObject.interestingFlag', false)
}
}
HQLでのみ左外部結合を実現できました
Class Transaction {
String someProperty
static hasMany = [reviews: Review]
static hasOne = [reviewQueue: ReviewQueue]
}
Class ReviewQueue {
Transaction transaction
Boolean isComplete
Boolean isReady
}
Class Review {
Transaction transaction
String reviewResult
}
def list = Transaction.executeQuery(
"select t.id, rq.isReady, rq.isComplete, count(r.transaction.id) " +
"from Transaction t " +
"join t.reviewQueue rq " +
"left outer join t.reviews r " +
"where rq.isComplete = false " +
"and rq.isReady = true " +
"group by t.id " +
"having count(r.transaction.id) = 0 " +
"order by rq.transaction.id ",
[max: 10, offset: 0])