mybatisのforeachの使い方を詳しく説明します。

6573 ワード

mybatisのmapper.xmlファイルを作る時によく使われています。sql文の検索条件を動的に生成します。この時はmybatisのforeachを使うことができます。
foreach元素の属性は主にitem、index、collection、open、separator、closeがあります。
  • item:セット内の要素反復時の別名であり、このパラメータは必須である。
  • index:listおよび配列において、indexは要素のシーケンス番号であり、mapにおいて、indexは要素のkeyであり、このパラメータはオプション
  • である。
  • open:foreachコードの開始記号は、一般的に(close=「)」と併用されます。n()、values()によく使われます。このパラメータはオプション
  • です。
  • separator:要素間のセパレータ、例えばin()の場合、separator="は、要素の中間に自動的に使用されます。"仕切り、カンマの手動入力によるsqlエラーを避けるために、in(1,2)のように。このパラメータはオプションです
  • close:foreachコードのクローズ記号は、一般的に、オープン=「(」と併用します。n()、values()によく使われます。このパラメータはオプションです
  • collection:foreachを行う対象として、Listオブジェクトはデフォルトではキーとして「list」を使用しています。配列オブジェクトはキーとしての代わりに「array」があります。Mapオブジェクトにはデフォルトのキーがありません。もちろん、参加時には@Param("keyName")を使ってキーを設定することができます。keyNameを設定すると、list、arrayは無効になります。パラメータの対象となるフィールドがある場合を除きます。例えば、Userに属性List idsがあれば。入参はUser対象です。このコレクション=「ids」です。もしUserが属性Ids idsを持っているならば。そのうち、Idsは対象で、Idsは属性List idを持っています。入参はUserオブジェクトで、collection=「ids.id」
  • foreachを使う時に一番重要なのは間違いやすいのがcollection属性です。この属性は必ず指定しなければなりませんが、その属性の値は違っています。主に次の3つの状況があります。
  • .入力されたのがシングルパラメータであり、パラメータタイプがListである場合、collection属性値はlistである。
  • 入力されたのが単一パラメータであり、パラメータタイプがarray配列である場合、collectionの属性値はarray.
  • である。
  • もし入ってきたパラメータが複数の場合、それらを一つのMapにパッケージする必要があります。もちろんシングルパラメータもmapにパッケージすることができます。実際にあなたがパラメータを入力した時、MyBatisの中にもMapにパッケージされます。mapのkeyはパラメータ名です。このときのcollection属性値は、入ってきたListまたはarrayオブジェクトが自分のパッケージのmapの中にあるkeyである。
  • 最後の条について、公式見解を見てみます。
    注意してください。リストの例や配列をパラメータの対象としてMyBatisに送ることができます。そうすると、MyBatisは自動的にMapに包装し、名前をキーにします。Listの例は「list」をキーとし、配列例のキーは「array」とする。
    したがって、マルチパラメータであろうと、シングルパラメータであろうと、arrayタイプであろうと、mapにカプセル化して転送することができる。転送がListであれば、mybatisはlistをkey、list値をobjectのmapとしてパッケージ化します。arrayであれば、arrayをkey、arrayの値をobjectのmapとしてパッケージ化します。もし自分でカプセル化するなら、collectionには自分のパッケージ化したmapのkey値を入れます。
    ソース分析
    公式文書はこれを使っていますので、説明は比較的短く、細部についても見落とされています。多くの学生が使っています。特にforeachという関数の中で、collection属性は何をしますか?注意事項がありますか?文書が不完全なので、これはソースコード解析の方法で各属性の関連要求を分析するしかないです。
    collection属性の用途は、入力を受信する配列またはListインターフェースで実現される。しかし、その名前の要求に対して、Mybatisは実現中にはちょっと分かりにくいので、特に注意しなければなりません。
    次にソースコードの分析を開始します。(メモはMybatis 3.0.5バージョンを使用しています。)
    まずMybatis SQLプロファイル解析を行うための入り口を見つけます。
    MapperMethod.javaクラスのpublicObject execute(Object[]args)は、この方法が実行されるエントリです。
    n集合クエリに対して、アプリケーションはselectForListまたはSelctForMap方法です。

    どの方法を呼び出しても、元JDKから入ってきたパラメータObject[]タイプに対して、getParam法でObjectに変換しますが、この方法は何をしますか?ソースの分析は以下の通りです。

    上の図の中で赤い二つのところは、一つのパラメータと複数のパラメータの処理方法が違っていることに驚きました。パラメータの個数が一つより大きい場合、Mapにパッケージされます。key値はMybatisのParam注釈を使用すると、このkey値を使用します。そうでなければ、デフォルトではデータ番号を統一して使用します。1から開始します。この問題を先にメモして、コードの解析を続けます。次はselectForList操作(他の操作は対応方法を適用します)であれば、Default Sql SessionのpublicListselectList(String statement、Object parameter、RowBounds rowBounds)方法を呼び出します。
    もう一つの発見がありました。ソースコードは以下の通りです。

    上のアイコンの赤い部分をパラメータにもう一度パッケージしました。コードを見てみます。

    パラメータタイプがListであれば、colleconでlistとして指定しなければならないことが分かりました。データグループであれば、collection属性でarrayとして指定しなければなりません。
    これで問題が明らかになります。パラメータなら、collectionの値はパラメータの種類によって決まります。
    複数の値であれば、注釈Paramで指定しない限り、数字の先頭であるため、collectionではどの値を指定しても無駄です。下図はdebug表示結果です。

    使い方
    シングルパラメータListタイプ
    
    <select id="countByUserList" resultType="_int" parameterType="list">
    select count(*) from users
     <where>
      id in
      <foreach item="item" collection="list" separator="," open="(" close=")" index="">
       #{item.id, jdbcType=NUMERIC}
      </foreach>
     </where>
    </select>
    テストコード:
    
    @Test
     public void shouldHandleComplexNullItem() {
      SqlSession sqlSession = sqlSessionFactory.openSession();
      try {
       Mapper mapper = sqlSession.getMapper(Mapper.class);
       User user1 = new User();
       user1.setId(2);
       user1.setName("User2");
       List<User> users = new ArrayList<User>();
       users.add(user1);
       users.add(null);
       int count = mapper.countByUserList(users);
       Assert.assertEquals(1, count);
      } finally {
       sqlSession.close();
      }
     }
    上記のcollectionはarrayであり、対応するMapperコード:
    
    public List dynamicForeach2Test(int[] ids);
    対応するテストコード:
    
    @Test
     public void dynamicForeach2Test() {
         SqlSession session = Util.getSqlSessionFactory().openSession();
         BlogMapper blogMapper = session.getMapper(BlogMapper.class);
         int[] ids = new int[] {1,3,6,9};
         List blogs = blogMapper.dynamicForeach2Test(ids);
         for (Blog blog : blogs)
         System.out.println(blog);  
         session.close();
     }
    3.自分でパラメータをMapにパッケージするタイプ
    
    <select id="dynamicForeach3Test" resultType="Blog">
         select * from t_blog where title like "%"#{title}"%" and id in
         <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
            #{item}
         </foreach>
     </select>
    上記のcollectionの値はidsであり、着信パラメータMapのkeyであり、対応するMapperコードである。
    
    public List dynamicForeach3Test(Map params);
    対応テストコード:
    
    @Test
      public void dynamicForeach3Test() {
        SqlSession session = Util.getSqlSessionFactory().openSession();
         BlogMapper blogMapper = session.getMapper(BlogMapper.class);
         final List ids = new ArrayList();
         ids.add(1);
         ids.add(2);
         ids.add(3);
         ids.add(6);
         ids.add(7);
         ids.add(9);
        Map params = new HashMap();
         params.put("ids", ids);
         params.put("title", "  ");
        List blogs = blogMapper.dynamicForeach3Test(params);
         for (Blog blog : blogs)
           System.out.println(blog);
         session.close();
       }
    注意sql文SELECT*FROM nujobs WHERE id IN()これはエラーとなりますので、最後にIdsの要素があると判断します。
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。