3

プラットフォームを学ぶために、GrailsでおもちゃのQ&Aサイトを作成しています。私には投稿とタグの2つのドメインがあり、それらの間には多対多の関係があります。タグ付きの投稿のリストを印刷したい。

N + 1選択の問題が発生するため、遅延フェッチを使用できません

左結合を使用し、結果を適切にページングできないため、イーガーフェッチも使用できません。

したがって、次のコードを使用してタグを手動でフェッチすることにしました。


static def getList(params) {

        ArrayList questions = Question.list(params)

        def questionMap = [:]
        questions.each {
            questionMap.put(it.id, it)
        }

        if(questions.size()>0) {
            Tag.executeQuery('SELECT q.id, t FROM Tag t JOIN t.questions q \
                                WHERE q.id in ( :list ) ', [ list:questions.collect{ it.id } ] ).each { questionMap.get(it[0]).tags.add(it[1]) }
        }

        return questions
}

ただし、ビューにタグを印刷すると、次のようになります。

<g:each in="${questions}" var="question">
   ${question.title} 
   <g:each in="${question.tags}" var="tag">
      ${tag?.text}
   </g:each>
</g:each>

とにかく、質問ごとにクエリが実行されます!ここで推奨されるアプローチは何ですか?

4

2 に答える 2

1

Tagコードの問題は、クエリの結果に対して何もしないことです。また、多対多の関係のための参加クラスを持つことはより良いアプローチです。たとえば、Spring Security Coreプラグインが表示されている場合は、、、UserおよびRoleと呼ばれる結合クラスがありUserRoleます。これがサンプルクラスです。

だからあなたへの私の提案は:

class Tag {
...
}

class Question{
...
}

class QuestionTag implements Serializable {
  Tag tag
  Question question
  static mapping = {
    id composite: ['tag','question']
    ...
  }
  //need to override equals and hashCode
}

タグの結果を保存するために、クラスの一時フィールドを追加できます。

class Question {def tags statictransients = ['tags']//hasManyを削除します。}

これで、を実行HQLし、質問リストで質問のインスタンスを探して、tags属性を設定できます。また、単一のクラスを返さない1つのHQLを使用しているため、結果はTagオブジェクトとしてマップされないため、アクセスは少し異なります。

HQLクエリは、クエリが個々のフィールドまたは計算値を選択したときに、ドメインクラスインスタンスまたは指定されたデータの配列を返すことができます

于 2013-03-20T02:50:24.533 に答える
0

あなたが言っています

「左結合を使用していて、結果を適切にページングできないため、熱心なフェッチも使用できません。」

session.createFilterを使用して、関連付けのページングを実行できます。

この例(著作権Burt Beckwith)は、BurtBeckwithの著書ProgrammingGrails from "Chapter 5、Hibernate、session.createFilter"からのものです。

// example from Burt Beckwith's book "Programming Grails", (c) Burt Beckwith
class Branch {
    String name
    List visits
    static hasMany = [visits: Visit]

    List<Visit> getVisitsByPage(int pageSize, int pageNumber) {
        Branch.withSession { session ->
            session.createFilter(visits, '')
                    .setMaxResults(pageSize)
                    .setFirstResult(pageSize * pageNumber)
                    .list()
        }
    }
}

この本を買うことをお勧めします

于 2013-03-20T05:30:40.653 に答える