ひっそりと生きるプログラマのブログ

日頃気になった事なりを書き留めるブログです。関心ごとは多くもう少し更新頻度を上げたいところです。

【Entity Framework】LINQ と Oracle の関数でマップされていないものを利用する(3)※固定値を関数に引数にとる場合

saboten-sakura.hatenablog.com

今回は前回より複雑なSQLを発行します。
TO_CHAR(DATE, 'D') で、指定した日付が何曜日かが取れます。
今回は上記の関数を投げて、特定の曜日のみ抽出する処理を目標とします。

流れとしては、途中まで1回目の流れです。
saboten-sakura.hatenablog.com

.net のメソッドを定義(Oracle 関数とマッピング用)

返す型は、 TO_CHAR なので string を返します。
引数は、TO_CHAR 2で二つなんですが、第1引数は任意の値で、第2引数は'D'を渡します。
なので、 .net では DateTime を引数として渡します。

public static string DayOfWeekString(this DateTime? value) => throw new NotImplementedException();

.net で定義したメソッドを Oracle 関数とマッピング

GetMethod で定義した MethodInfo を取得します。

var method = typeof(StringExtension).GetMethod(nameof(StringExtension.DayOfWeekString), new Type[] { typeof(DateTime) })!;

取得した MethodInfo と Oracle の関数を定義付けします。

modelBuilder.HasDbFunction(method).HasTranslation(translation =>
new SqlFunctionExpression(
    "TO_CHAR",
    new SqlExpression[]
    {
        new SqlConstantExpression(
            Expression.Constant("D"),
            new StringTypeMapping(
                "VARCHAR2",
                DbType.String)),
        translation.First()
    },
    true,
    new bool[]
    {
        false,
        false
    },
    typeof(string),
    new StringTypeMapping(
        "VARCHAR2",
        DbType.String)
    )
);

上記を定義した後に、以下のコードを実装。

var context = new SampleDbContext();
var items = (from m in context.SampleTables 
             where
                m.SampleDate.DayOfWeekString() == "3"
             select m);
foreach (var item in items)
{
    Console.WriteLine($"{item.Id} - {item.SampleDate?.ToString("ddd")}");
}

で、出力した SQL がこちら。

SELECT "s"."ID", "s"."SAMPLEDATE", "s"."SAMPLENUMBER"
FROM "SAMPLETABLE" "s"
WHERE TO_CHAR("s"."SAMPLEDATE", 'D') = '3'