Golangに「ent」というORMがあります。
もともとはFacebookが開発したパッケージで型安全でありクエリ用の関数を自動生成してくれたりと大変使い勝手の良いORMです。
そんな「ent」ですが、クエリビルダーの仕様を誤解していて半日ほどハマってしまいました。
下記のようなコードがあったとします。
query := client.Query()
if limit > 0{
query.Limit(limit)
}
ids := []int{1,2,3,4,5}
for _, id := range ids {
query.Where(user.IdIn(id)).All(ctx)
}
このコードではAll()メソッドの実行を契機にDBへクエリが投げられるのですが、実はWhere()で設定した条件はイテレーションを跨いで保持されます。
entパッケージで定義されているクエリビルダーは内部に検索条件を保持するスライスを持っている構造体で、All()などでクエリを実行しても検索条件をクリアしません。
なので変数として定義したクエリビルダーを使い回してしまうと検索条件がイテレーションを跨いで有効になってしまいます。
もし多数のデータを取得しないといけないけれど、事情があってクエリを分割して投げなければいけないときはイテレーションごとにクエリビルダーを定義してあげましょう。
ids := []int{1,2,3,4,5}
for _, id := range ids {
query := client.Query()
if limit > 0{
query.Limit(limit)
}
query.Where(user.IdIn(id)).All(ctx)
}