【问题标题】:Grails hasMany and criteria not working as expectedGrails hasMany 和标准没有按预期工作
【发布时间】:2015-03-20 17:26:34
【问题描述】:

我有两个具有 hasMany 关系的模型

class Puturru implements Serializable {
    String name

    Set<Fua> fuas

    static hasMany = [fuas: Fua]

    static constraints = {
        fuas(nullable: true)
    }
}

class Fua {

    String name

    static constraints = {
    }
}

运行下一个测试时,我得到一个 LazyInitializationException

 void "test something"() {
    given:
    def puturrus

    Puturru.withNewSession { session ->
        p = Puturru.build()
        Fua f
        for (int i = 0; i < 10; i++) {
            f = Fua.build()
            p.addToFuas(f)
        }
        f.save(failOnError: true, flush: true)

    }

    when:
    Puturru.withNewSession {

        puturrus = Puturru.createCriteria().listDistinct {

            fetchMode("fuas", FetchMode.JOIN)
        }

    }

    then:
    Puturru.withNewSession {
        assert puturrus.fuas*.name.size() > 0

    }

    p.fuas.each { it.delete() }
    p.delete()
}

如果我设置 puturrus 映射

static mapping = {
    fuas lazy: false
}

然后检索所有元素,尽管它使用多个选择,否则它使用此查询

select ...
from puturru ...
left outer join puturru_fua fuas2_ on this_.id=fuas2_.puturru_fuas_id

我无法在实际应用中设置映射,因为我不想在所有情况下都获取所有条目。对我来说,我似乎遗漏了一些东西来使标准比中间表更进一步。

我正在使用 grails 2.3.6 和休眠 3.6.10.8。

有人知道为什么没有得到“fuas”对象吗?

编辑 1:更多信息

我一直在尝试对域进行一些更改并进行测试以找出问题所在。

在@sudhir 的建议之后,我开始玩加入我将条件更改为类似

    puturrus = Puturru.createCriteria().listDistinct {
        fuas {
        }
    }

那么gorm和hibernate生成的查询是

select ...
from puturru this_
inner join puturru_fua fuas3_ on this_.id=fuas3_.puturru_fuas_id
inner join fua fuas_alias1_ on fuas3_.fua_id=fuas_alias1_.id

这次我们得到了所有条目,但没有得到它们与 puturrus 域的关系。我们妥协并提出第二个查询只是为了获取关联,所以目前第二个会话块是

Puturru.withNewSession {

    puturrus = Puturru.createCriteria().listDistinct {
        fuas {
        }
    }

    Puturru.createCriteria().listDistinct {
        fetchMode("fuas", FetchMode.JOIN)
    }
}

这比我之前在标准会话中遍历所有 puturrus 和所有 fuas 的方法要好得多,但我认为仍然不是最佳的,所以有什么方法可以同时获取数据和关联一个查询?

【问题讨论】:

  • 你没有在给定的末尾保存 Putturu:块。为什么你在所有这些地方都使用 withNewSession,它根本不需要。另外,请注意,fetchmode join 会给你重复的结果,你可能想使用 fetchmode FM.SELECT
  • 实际上是构建方法,它是构建测试数据插件的一部分,保存。我编写这段代码只是为了重现我在现实世界应用程序中发现的情况,在现实世界中,拆分三个会话是有充分理由的。我也尝试了 FM.SELECT,但没有成功。
  • 尝试在您的条件中添加 join 'fuas',并删除 fetchMode,这样它就像条件.listDistinct { join "fuas"}
  • @sudhir 如果我这样做,查询有两个内部连接,但仍然不起作用。但是,如果我使用调试器检查元素,则此查询 select fuas0_.puturru_fuas_id as puturru1_1_0_, fuas0_.fua_id as fua2_0_ from puturru_fua fuas0_ where fuas0_.puturru_fuas_id=? 然后元素在会话之外可用。

标签: grails grails-orm hibernate-criteria


【解决方案1】:

您可以使用以下 hql

Puturru.executeQuery("select p from Puturru p inner join fetch p.fuas as f where p.id = :id", [id:id])

如果你想让所有 Puturru 删除 where 条件

【讨论】:

  • 你说得对,这很有用,因为代码像这个例子一样简单,但真正的代码要复杂得多,它包括其他几个域,我们不想要这样的大型 hql 查询。
【解决方案2】:

我们使用 createAlias 找到了合适的解决方案

Puturru.withNewSession {
    puturrus = Puturru.createCriteria().listDistinct {
        createAlias("fuas", "fuas", CriteriaSpecification.LEFT_JOIN)
    }
}

实际上它似乎是 Hibernate 3.6 中的一个错误,已经在 Hibernate 4 中修复了

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多