拡張メソッドによってLINQ to SQLがだまされるのはなぜですか?今何?
-
03-07-2019 - |
質問
Event
クラスを検討し、 DateTime
をUTC日付としてDBに保存します。特定のタイムゾーンの現在の日付に基づいてフィルター処理された範囲を返すだけです-簡単ですか?
これは正常に動作します:
IQueryable<Event> test1 = this.GetSortedEvents().Where(e => e.FinishDateTime.Date >= DateTime.UtcNow.Date);
これも正常に動作します:
IQueryable<Event> test2 = this.GetSortedEvents().Where(e => e.FinishDateTime.AddHours(3).Date >= DateTime.UtcNow.AddHours(3).Date);
..さらにタイムゾーンの要件を満たします。
ここで、この特定の変換をこの拡張メソッドに移動できると考えています:
public static DateTime RiyadhTimeFromUtc(this DateTime utcTime) { return utcTime.AddHours(3); }
これは機能しません:
IQueryable<Event> test3 = this.GetSortedEvents().Where(e => e.FinishDateTime.RiyadhTimeFromUtc().Date >= DateTime.UtcNow.RiyadhTimeFromUtc().Date);
..そして、私はこのNotSupportedExceptionを受け取ります:メソッド 'System.DateTime RiyadhTimeFromUtc(System.DateTime)'にはSQLへのサポートされた変換がありません。
同一のコードが拡張メソッドにない場合、コンパイラーが喜んでSQLに変換したため、これは明らかにゴミです。
「サポートされていないSQLへの変換」に遭遇しました;前に特定のタイプと最近のDateTimeの問題。しかし、上記のテストとこのリンクは、AddHoursメソッドがSQL翻訳でサポートされています。
誰かが私がここで間違っていることを教えてくれたら(またはこの問題に対する別の回避策)、私は本当に感謝します。
解決
式ツリーの観点から考える必要があります。これは、Linq-to-SQLがクエリを解析してSQLに変換する方法です。
ツリーを調べると、 DateTime
オブジェクトが表示され、そこで呼び出されたメソッドがサポートされているメソッド( Add
、 AddHours
など)。メソッドを直接使用する場合は正常に機能します。
他の拡張メソッドを使用すると、そのメソッドの本体に関する情報が式ツリーにないため、ILに隠されているため、そのメソッドの内部を調べてその機能を確認することはできません。そのため、Linq-to-SQLはコンテンツが何であるかを判断できないため、拡張メソッドのコンテンツがサポートされているかどうかは関係ありません。
メソッドを作成するポイントはカプセル化と情報の隠蔽であり、これは通常アプリケーション開発でうまく機能しますが、残念なことにここでは情報を見る必要があるLinq-to-SQLからの情報を隠しています。
編集された質問への回答-これをどのように解決しますか? Linq式内で日付の計算を保持したい場合、クエリを効率的にするためにできる唯一のことは、拡張メソッドを使用せず、 AddHours(3)
を< code> DateTime オブジェクト。
これはLinqの不幸な制限の1つです。多くの事柄と同様に、ソースの範囲に共通の構文を提供しながら、ソースのプロバイダーがサポートできる操作/サポートする操作に異なる制限と制限があります(たとえば、これはLinq-toで完全に機能します) -オブジェクトを実行するために式ツリーを変換する必要がないため)。
他のヒント
LINQ-to-SQLが RiyadhTimeFromUtc
が実際には AddHours(3)
の単なる呼び出しであると判断できるように思われるコードのかなり洗練された分析。書いたとしましょう:
public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
{
if (Random.GetInt() < 99) {
return utcTime.AddHours(3);
} else {
return utcTime.AddDays(5);
}
}
それをどのようにSQLに変換しますか? このディスカッション詳細情報をご覧ください。