Grails 准则使用「;“内部连接”;取而代之的是;“左连接”;默认情况下,使我的查询不是按我计划的方式工作

Grails 准则使用「;“内部连接”;取而代之的是;“左连接”;默认情况下,使我的查询不是按我计划的方式工作,grails,gorm,Grails,Gorm,问题是:在这个特定示例中,如何使GORM生成左连接而不是内部连接 试验台: 给定A类、B类和C类: class A{ B someObject } class B{ C importantObject } class C{ boolean interestingFlag } 我想列出一个类的所有元素: 他们的B.C对象为null或 他们的B.C对象兴趣标志值为false 到目前为止,我尝试的是: 此方法生成正确的列表,其中B.C为null(条件2已注释掉)或正确

问题是:在这个特定示例中,如何使GORM生成左连接而不是内部连接

试验台:

给定A类、B类和C类:

class A{
    B someObject
}

class B{
    C importantObject
}

class C{
    boolean interestingFlag
}
我想列出一个类的所有元素:

  • 他们的B.C对象为null或
  • 他们的B.C对象兴趣标志值为false
到目前为止,我尝试的是:

此方法生成正确的列表,其中B.C为null(条件2已注释掉)或正确的列表,其中B.C.interestingFlag=false(无论条件1是否已注释掉)。当两个条件都未注释时,它只返回元素列表,其中a.B.C.interestingFlag=false(忽略a.B.C=null条件)

编辑: 根据评论中的要求,我正在粘贴hibernate生成的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=?)))
当我直接将其复制并粘贴到pgAdmin查询工具中,并更改了一些内容(内部连接更改为左连接,并提供了interestingFlag=“false”参数)时,一切都按照我的要求工作(我得到了a.B.C=null和a.B.C.importantFlag=false对象)


使用left join来实现这一点。这应该行得通,但我还没有现场测试过

def result = A.withCriteria{
    someObject {
        createAlias("importantObject", "io", CriteriaSpecification.LEFT_JOIN)
        or{
            isNull('importantObject') // conditional 1
            eq('io.interestingFlag', false) // conditional 2            
        }  
    } 
}
艾德:基于这篇文章:这也应该有效:

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)
    } 
}

测试和工作解决方案:

    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)
        } 

    }

我只能通过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])

尝试在数据源中启用logSql=true,并查看此qquery生成的sql。请在这里发布。@TomaszKalkosiński根据请求,这里是hibernate sql输出。我知道如何调整查询以使其按我所希望的方式工作。我不知道如何让GORM生成正确的查询它们都生成了错误。解决方案1:Class org.hibernate.QueryException Message无法解析属性:importantObject of:A。解决方案2:groovy.lang.MissingMethodException Message没有方法签名:AController.importantObject()适用于参数类型:(javax.persistence.criteria.JoinType,AController$\u list\u closure1\u closure2\u closure3)值:[左,a控制器$\u列表\u关闭1\u关闭2_closure3@40230d]这很奇怪,因为消息指示对象上的错误,而importantObject位于someObject闭包中。至于解决方案1,尝试在某个对象上创建alias,看看这是否有帮助。将alias更改为createAlias(“someObject.ImportantoObject”、“io”、CriteriaSpecification.LEFT_JOIN”)后运气不佳。现在它找不到“io()method”@AndrzejBobak,我认为你的问题有问题,它也会影响你的查询。您提出的结构与您的问题和查询不匹配。如果没有正确的结构,我们无法继续前进,这样我们就可以修复您的查询。这是我的示例项目中的内容的精确副本。为了回答这个问题而设置它并生成sql输出花了我大约10分钟的时间。我使用Grails2.2.1和Postgresql 8.3。如果你感兴趣,我可以给你一份这个项目的副本,但它太小了,可以在几分钟内创建(3个类,每个类有1个字段,生成的视图+支架)。我真的不明白你所说的“我提出的结构与我的问题和疑问不符”是什么意思。先生,你是个救命恩人!!CriteriaSpecification.LEFT_联接已被弃用。对于最新版本,请使用JoinType.LEFT\u OUTER\u JOIN。资料来源:
    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)
        } 

    }
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])