1

私が取り組んでいるプロジェクトには、あるコード ブランチと別のコード ブランチでは動的ファインダーの動作が異なるコードがいくつかあります。

このコード行は、所属しているブランチに関係なく、すべての広告主 (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
}

これで、動的ファインダーと同じように、単一の結果が返されます。maxResults100K までクランクアップすると、8 つの結果すべてが得られます。

それで、何が起こっているのですか?結合または熱心なフェッチ (またはその両方) により、何千もの重複を返す SQL が生成されたようです。Grails の動的ファインダーは、デフォルトで個別の結果を返さなければならないので、それらを制限していないときは、何もおかしなことには気付きませんでした。しかし、制限を設定すると、レコードは ID 順に並べられているため、最初の 25 レコードはすべて重複レコードになり、1 つの異なるレコードのみが返されます。

結合と熱心なフェッチについては、そのコードが解決しようとしていた問題が何であるかがわからないため、それが必要かどうかはわかりません。問題は、このコードをクラスに含めると、なぜ多くの重複が生成されるのかということです。

4

2 に答える 2

1

何百ものクエリが作成されたため、特定のレポートのレンダリングを高速化するために、熱心なフェッチが追加された (多くのレベルの深さ) ことがわかりました。オンデマンドで熱心にフェッチする試みが行われましたが、他の開発者はファインダーや Grails 基準を使用して 1 レベル以上の深さまで進むことが困難でした。

したがって、上記の質問に対する一般的な答えは次のとおりです。他の場所で巨大な悪夢を引き起こす可能性のあるデフォルトの熱心な代わりに、ツリーの複数のレベルを下ることができる単一のクエリで熱心なフェッチを行う方法を見つける必要があります。

次の質問は、どうやって?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その後、デフォルトでクラスを怠惰なままにすることができます-これはシナリオ用に間違いなくあるべきです。

于 2013-04-25T16:55:29.620 に答える
0

クエリが重複を取得しているため、この 25 レコードの制限が同じデータを返す可能性があり、その結果、個別のレコードが 1 レコードに減少します。

equals()クラスにandを定義するようにhashCode()してください。特に、複合主キーを持つものがある場合、または として使用される場合はそうですhasMany

また、可能性を排除しようとすることをお勧めします。フェッチとイーガーを 1 つずつ削除して、結果データにどのように影響するかを確認します (制限なし)。

于 2013-04-23T11:09:46.453 に答える