slim3(GAE/J)で検索条件で絞り込んだ結果に対してのページング
問題
gaeではページングをしようとしてoffsetに1000以上の値をセットすると、以下のようなエラーになってしまう。
java.lang.IllegalArgumentException: offset may not be above 1000
当然gae上のフレームワークであるslim3で以下のように書いても同じこと。
Datastore.query(meta)
.offset(1000)
以下のページでやり方を紹介しているが、この方法は全件検索の結果に対してしか有効ではない。
http://code.google.com/intl/ja/appengine/articles/paging.html
また、カーソルを使ったやり方も紹介されているが、それって「次へ」っていうナビゲーションしかないページングでは使えるけど、それ以外のページングにも使えるのか?
http://sites.google.com/site/slim3documentja/documents/slim3-datastore/queries-and-indexes#TOC-20
ちなみに環境は下記
- gaeは1.3.2
- slim3は1.0.1
というわけで
というわけで、slim3のModelQueryを拡張したクラスと、それを返す以下のようなクラスを作った。
これでアプリ側では以下のような形で1000を超えたoffsetでも気にせずページングをさせることができる。
MyDatastore.query(meta) .offset(1000) .limit(50)
package nanzokore.datastore; import org.slim3.datastore.ModelMeta; import org.slim3.datastore.ModelQuery; public class MyDatastore { public static <M> ModelQuery<M> query(ModelMeta<M> modelMeta){ return new MyModelQuery<M>(modelMeta); } }
package nanzokore.datastore; import java.util.List; import org.slim3.datastore.ModelMeta; import org.slim3.datastore.ModelQuery; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.Transaction; public class MyModelQuery<M> extends ModelQuery<M>{ protected static final int MAXIMUM = 1000; protected Integer offset = 0; protected Integer limit = 0; public MyModelQuery(ModelMeta<M> modelMeta) throws NullPointerException { super(modelMeta); } public MyModelQuery(ModelMeta<M> modelMeta, Key ancestorKey) throws NullPointerException { super(modelMeta, ancestorKey); } public MyModelQuery(Transaction tx, ModelMeta<M> modelMeta, Key ancestorKey) throws NullPointerException { super(tx, modelMeta, ancestorKey); } @Override public ModelQuery<M> offset(int offset) { this.offset = offset; return this; } @Override public ModelQuery<M> limit(int limit) { this.limit = limit; return this; } @Override public List<M> asList() { super.offset(0); super.limit(Integer.MAX_VALUE); List<M> entries = super.asList(); int lastIndex = entries.size(); int fromIndex = Math.min(this.offset, lastIndex); int toIndex = (limit == 0) ? lastIndex : Math.min(offset + limit, lastIndex); return new ArrayList<M>(entries.subList(fromIndex, toIndex)); } }
備考
バグってたらすいません。教えていただけるとうれしいです。
(2010/04/25)InMemorySortができていなかったので、修正した。