Pandora Pocket

IT系と日常系の備忘録。三日坊主。

ListからSQL検索条件を生成するLINQ

.NET Core 3.1対応をしているのですが、それに伴ってEntity Framework Coreもv3にあげたところ、LINQのクライアントサイド評価が行われなくなったことでいくつかのクエリが使えなくなったため、いろいろ調べながら対応しています。

対応が必要だったうちの一件が下記のようなもの。

class TBL {
string Data1;
string Data2;
}

このようなクラスを保持するリスト(List)に対して、

.Where(x => list.Any(l => l.Data1 == x.Data1 && l.Data2 = x.Data2))

のように、含まれている値と一致するレコードだけを取得するというものです。
SQLにしてみれば

WHERE (TBL.Data1 == [listの値1-1] && TBL.Data2 == [listの値1-2])
OR (TBL.Data1 == [listの値2-1] && TBL.Data2 == [listの値2-2])
・・・

みたいな感じ。
LINQ to SQLだとこのクエリ、SQLに変換してサーバーサイドで実行してくれないんですね。
式木をうまいことこねこねして動的に.Where内の値を生成するようにしようと思ったのですが、今の力量だとちょっと手間取りそうで、それに時間をかけてられないこともあり、とりあえずLINQを使わずFromSqlRawで直接SQLを実行することにしました。
SQLで実行するにしてもWHERE句に指定する条件はリストから動的に生成する必要があります。

そんな時に便利なのが下記のLINQ

var param = list
.Aggregate(
string.Empty,
(current, tbl) => current + $" OR ([Data1] = '{tbl.Data1}' AND [Data2] = {tbl.Data2}) ");

これならlistに格納されている値分のOR条件式が一つの文字列に吐き出されるので、あとは

var sql = $@"SELECT * FROM TBL
WHERE (1=0)
{param}";

こんな感じでSQLにぶち込んで、EFなりDapperなりに渡してやればOK。