ORMは、リーク> 。最終的にはすべてそうです。 Ectoは若いです(つまり、OR
する能力しか得られませんでした where句を一緒に
考えられるオプションを調査します。リクエストに参加しているのはあなただけではありません。フラグメント内のリストを理解できない(order_by
の一部であるかどうかにかかわらず) またはwhere
または他の場所)が Ecto issue#1485
で言及されています 、 StackOverflow
、Elixirフォーラム
そしてこれは
実験#1: 最初にKernel.apply/3
を使用してみてください。 リストをfragment
に渡します 、しかしそれは機能しません:
|> order_by(Kernel.apply(Ecto.Query.Builder, :fragment, ^ids))
実験#2: そうすれば、文字列操作で構築できるかもしれません。 fragment
を与えるのはどうですか リストから取得するのに十分なプレースホルダーを備えた実行時に作成された文字列:
|> order_by(fragment(Enum.join(["FIELD(id,", Enum.join(Enum.map(ids, fn _ -> "?" end), ","), ")"], ""), ^ids))
FIELD(id,?,?,?)
を生成するのはどれですか 与えられたids = [1, 2, 3]
。いいえ、これも機能しません。
実験#3: IDから構築された最終的なSQL全体を作成し、生のID値を作成された文字列に直接配置します。恐ろしいだけでなく、それも機能しません:
|> order_by(fragment(Enum.join(["FIELD(id,", Enum.join(^ids, ","), ")"], "")))
実験#4: これは私が言及したそのブログ投稿に私を連れて行きます。その中で、作者はor_where
の欠如をハックしています まとめる条件の数に基づいて事前定義されたマクロのセットを使用する:
defp orderby_fragment(query, [v1]) do
from u in query, order_by: fragment("FIELD(id,?)", ^v1)
end
defp orderby_fragment(query, [v1,v2]) do
from u in query, order_by: fragment("FIELD(id,?,?)", ^v1, ^v2)
end
defp orderby_fragment(query, [v1,v2,v3]) do
from u in query, order_by: fragment("FIELD(id,?,?,?)", ^v1, ^v2, ^v3)
end
defp orderby_fragment(query, [v1,v2,v3,v4]) do
from u in query, order_by: fragment("FIELD(id,?,?,?)", ^v1, ^v2, ^v3, ^v4)
end
これは、いわば「グレインを備えた」ORMを使用して機能しますが、使用可能なフィールドの数が有限で管理しやすい必要があります。これはゲームチェンジャーである場合とそうでない場合があります。
私の推奨事項:ORMのリークを回避しようとしないでください。あなたは最高のクエリを知っています。 ORMがそれを受け入れない場合は、生のSQLを使用して直接記述し、ORMが機能しない理由を文書化します。関数またはモジュールの背後でシールドして、実装を変更する将来の権利を留保できるようにします。ある日、ORMが追いついたら、システムの他の部分に影響を与えることなく、適切に書き直すことができます。