避免在Grails / Hibernate中选择N + 1

时间:2012-05-10 18:43:39

标签: hibernate grails orm

更新:可能与2.0.1中的Grails错误有关: http://comments.gmane.org/gmane.comp.lang.groovy.grails.user/125400

更新2 :这让我最接近,但分页不起作用。在这种情况下,返回所有的A,每个都有他们的B列表,每个B都带有C.一旦我添加了偏移和最大值,事情就搞砸了。例如,在这种情况下,不会返回10个A.也许会返回1 A和9 B.

def results = A.list([fetch:[bees: "eager"], offset: 0, max: 10]);

问题:我想在一个查询中加载所有A,它们关联的B和B的关联C.在一个查询中检索所有A及其关联的B非常简单。我不知道如何加载所有B的C作为同一个查询的一部分。按设计,B - >的默认映射; C应该是急切的,因为我在加载B时总是想要C。我认为设置这个映射可以解决问题。

class A {
    static hasMany = [
            bees:  B,
    ]
}

class B {
    C c;

    static belongsTo = [a: A]

    // also tried this and every possible combination
    //static fetchMode = [c: 'eager']

    static mapping = {
        c fetch: 'join'
        // c lazy: 'false'
    }
}

class C {
    String someField;
}

这是我的疑问:

def results = A.executeQuery("from A a left join fetch a.bees",
                     [max: pageSize, offset: offset]);

如果我现在迭代结果:

for (A a in results) {
   for (B b in a.bees) {
      println "B: " + b; // this is OK, B is already loaded
      println "B's C: " + b.c.someField; // C not loaded
   }
}

当我迭代结果时,b.c.someField行将导致每个B执行“select”。这很糟糕我想尽可能避免这种情况。我发布了一个解决方案,作为一个使用第二个查询和查找地图的答案,但必须有更好的方法。

我在“更新2”中发布的查询让我非常接近。实际上它工作正常,直到我使用分页(具有偏移/最大)。 Grails用户指南提到“fetch:'join'可能会导致带有偏移量/最大值的查询出现问题,但它不会涉及任何细节。注意:为了使此查询起作用,我必须禁用hibernate查询缓存,如由于Grails 2.0.1中的错误而“更新1”。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

解决方法是简单地获取所有A及其相关的B。

一旦你有了这个,你可以在不进行任何查询的情况下获得所有C的ID:

def cIds = [] as Set;

for (A a : results) {
    for (B b : a.bees) {
        // Note: getCId() is a special method which does not cause a query
        cIds.add(b.getCId());
    }
}

获得所有C ID后,您可以使用第二个查询从数据库中获取这些ID,并将它们存储到地图中以便稍后查找:

def cMap = [:]
def cees = C.getAll(cIds.toList());
for (C c : cees) {
    cMap[c.id] = c;
}

现在,您可以迭代原始结果集以打印出C的字段:

for (A a : results) {
    for (B b : a.bees) {
        println "The meaning of life is " + cMap[b.getCId()].someField;
    }
}

总查询数= 2(一个用于原始左连接,另一个用于获取所有C)

如果有人有更好的解决方案,请发帖。

答案 1 :(得分:0)

根据Grails的文档,GORM默认延迟加载。这是文档http://grails.org/doc/1.1/guide/5.%20Object%20Relational%20Mapping%20(GORM).html

的链接

我不清楚你在这里问的是什么