【问题标题】:Can a Grails dynamic finder be broken by application code?Grails 动态查找器会被应用程序代码破坏吗?
【发布时间】:2013-04-26 00:55:29
【问题描述】:

我正在处理的项目中有一些代码,其中动态查找器在一个代码分支中的行为与在另一个代码分支中的行为不同。

这行代码返回我所有的广告客户(其中有 8 个),无论我在哪个分支。

Advertiser.findAllByOwner(ownerInstance)

但是当我开始添加条件时,事情变得很奇怪。在分支 A 中,以下代码返回我的所有广告客户:

Advertiser.findAllByOwner(ownerInstance, [max: 25])

但在分支 B 中,该代码仅返回 1 个广告商。

应用程序代码的更改似乎不会影响动态查找器的工作方式。我错了吗?还有什么可能导致这不起作用吗?

编辑

我被要求发布我的班级定义。我不会发布所有内容,而是发布我认为重要的部分:

static mapping = {
    owner fetch: 'join'
    category fetch: 'join'
    subcategory fetch: 'join'
}

static fetchMode = [
      grades: 'eager',
      advertiserKeywords: 'eager',
      advertiserConnections: 'eager'
]

此代码存在于分支 B 但不存在于分支 A。当我将其拉出时,现在一切正常。

我决定用这个代码做更多的挖掘,看看我能观察到什么。当我使用withCriteria 而不是动态查找器时,我发现了一些有趣的东西:

Advertiser.withCriteria{owner{idEq(ownerInstance.id)}}

我发现这返回了数千个重复项!所以我尝试使用listDistinct:

Adviertiser.createCriteria().listDistinct{owner{idEq(ownerInstance.id)}}

现在这将返回我的所有 8 个广告客户,并且没有重复。但是如果我试图限制结果呢?

Advertiser.createCriteria().listDistinct{
    owner{idEq(ownerInstance.id)}
    maxResults 25
}

现在这会返回一个结果,就像我的动态查找器一样。当我将 maxResults 提高到 100K 时,现在我得到了全部 8 个结果。

那么发生了什么?似乎连接或急切获取(或两者)生成的 sql 返回了数千个重复项。默认情况下,Grails 动态查找器必须返回不同的结果,所以当我不限制它们时,我没有发现任何奇怪的东西。但是一旦我设置了一个限制,由于记录是按 ID 排序的,前 25 条记录都将是重复记录,这意味着只会返回一个不同的记录。

关于join和eager fetching,我不知道这段代码试图解决什么问题,所以我不能说是否有必要;问题是,为什么在我的班级中有这段代码会产生这么多重复?

【问题讨论】:

  • 你能分享一下广告商的定义吗?您确定两者中的 ownerInstance 相同吗?
  • 您的应用程序不应影响此行为。更可能的原因是您指向不同分支中的两个不同数据库,或者一个分支具有另一个没有的验证,并且您在夹具或 Bootstrap 中创建 8 个广告商并且创建失败。
  • 记住,第一行代码给了我所有我的广告商不管我在哪个分支。只有当我添加条件时我在分支 B 中观察到这种行为。所以我认为这排除了上面 cmets 中提到的可能性。
  • 您可以启用 sql 日志记录来检查生成的查询。
  • 最常见的答案是 2 个不同的数据库。并同意 proflux:“你的应用程序不应该影响这种行为。”

标签: grails branch grails-orm dynamic-finders


【解决方案1】:

我发现添加了 Eager fetching(许多级别的深度)是为了加快某些报告的呈现速度,因为正在进行数百次查询。曾尝试过按需获取,但其他开发人员很难使用查找器或 Grails 标准深入一层以上。

所以上述问题的一般答案是:我们需要找到一种方法来对单个查询进行渴望获取,而不是默认情况下会在其他地方造成巨大的噩梦。树下一层

下一个问题是,怎么做? Grails 对它的支持不是很好,但是可以通过简单地使用 Hibernate 的 Criteria 类来实现。这是它的要点:

        def advertiser = Advertiser.createCriteria()
            .add(Restrictions.eq('id', advertiserId))
            .createCriteria('advertiserConnections', CriteriaSpecification.INNER_JOIN)
                .setFetchMode('serpEntries', FetchMode.JOIN)
                .uniqueResult()

现在广告客户的advertiserConnections 将被急切获取,advertiserConnections'serpEntries 也将被急切获取。您可以根据需要沿着树向下走。然后你可以默认让你的类保持惰性——它们绝对应该用于hasMany 场景。

【讨论】:

    【解决方案2】:

    由于您的查询正在检索重复项,因此 25 条记录的限制有可能返回相同的数据,因此您的不同记录将减少到一条记录。

    尝试为您的类定义equals()hashCode(),特别是如果您有一些具有复合主键或用作hasMany

    我还建议您尝试消除这些可能性。把 fetch 和 eager 一个一个去掉,看看它如何影响你的结果数据(没有限制)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-02
      • 2011-08-22
      • 2013-06-30
      • 1970-01-01
      • 2013-12-02
      • 2015-03-03
      • 1970-01-01
      相关资源
      最近更新 更多