sql >> データベース >  >> RDS >> Mysql

可変アリティを備えたEctoクエリとカスタムMySQL関数

    ORMは、リーク> 。最終的にはすべてそうです。 Ectoは若いです(つまり、ORする能力しか得られませんでした where句を一緒に30日前 )、したがって、高度なSQL旋回を考慮したAPIを開発するほど成熟していません。

    考えられるオプションを調査します。リクエストに参加しているのはあなただけではありません。フラグメント内のリストを理解できない(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が追いついたら、システムの他の部分に影響を与えることなく、適切に書き直すことができます。



    1. C#を使用して000webhost上のmysqlに接続する

    2. mysqliまたはPDO-長所と短所は何ですか?

    3. /var/lib/mysql/mysql.sockファイルがありません

    4. Postgresのパスワード認証が失敗する