2009-03-04 8 views
4

私のEventクラスを考えてみましょう。そして、私はDateTimeをUTCの日付としてDBに保存しています。私は単に、特定のタイムゾーンで現在の日付に基づいてフィルタリングされた範囲を返すことを望んでいます。また、これは正常に動作しますLINQ to SQLが拡張メソッドで騙されたのはなぜですか?今何?

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に変換してくれたので、これは明らかにごみです。

特定のタイプと最近のDateTimeでは、以前は「SQLへの変換はサポートされていません」という問題が発生しました。しかし、上記のテストとthis linkは、AddHoursメソッドがSQL変換でサポートされるべきであることを証明しています。

誰かが私がここで間違っていること(またはこの問題に対する別の回避策)を教えてもらえれば、本当に感謝しています。

答えて

9

Linq-to-SQLがクエリを解析してSQLに変換する方法である、式ツリーの観点から考える必要があります。それはDateTimeオブジェクトを参照し、それに呼び出されるメソッドがサポートされたものの一つであるかどうかをチェックしますツリー(AddAddHours、など)を調べるときは、直接メソッドを使用する場合

は、それが正常に動作します。

他の拡張メソッドを使用すると、そのメソッドのボディに関する情報が式ツリーにないため、そのメソッドを見てそのメソッドを見ることができず、ILに隠されています。したがって、Linq-to-SQLは内容が何であるかを調べることができないので、拡張メソッドの内容がサポートされているかどうかは関係ありません。

メソッドの作成のポイントは、カプセル化と情報隠蔽ですが、通常はアプリケーション開発ではうまくいきますが、残念ながらLinq-to-SQLの情報を隠すことになります。


編集した質問に対する回答 - これをどのように解決しますか? Linq式内で日付計算を維持したい場合は、クエリを効率的にするためにできるのは、拡張メソッドを使用しないで、DateTimeオブジェクトに直接AddHours(3)を直接使用するだけです。

これはLinqの不幸な制限の1つです。多くのものと同様、いくつかのソースに共通の構文を提供する一方で、ソースのプロバイダがサポートできる操作にはさまざまな制限や制限があります(たとえばLinq-toでは完全にうまく動作します-Objectは、それを実行するために式ツリーを変換する必要がないため)。

+0

これは素晴らしい説明です。しかし、私はまだそれが私にどのように役立つのかわかりません。私の問題に対する具体的な提案はありますか? –

+0

私はそれを行うためにLinq Expressionsを使用しようとしています - http://www.albahari.com/nutshell/predicatebuilder.aspxご協力ありがとう –

4

RiyadhTimeFromUtcが実際にAddHours(3)への呼び出しであることをLINQ-to-SQLが知ることができるように思えるのは、コードのかなり洗練された分析を行う必要があるということです。あなたが書いてくれたとします:

public static DateTime RiyadhTimeFromUtc(this DateTime utcTime) 
{ 
    if (Random.GetInt() < 99) { 
     return utcTime.AddHours(3); 
    } else { 
     return utcTime.AddDays(5); 
    } 
} 

それはどのようにSQLに変換されますか?詳細については、this discussionを参照してください。

+0

ありがとうございました。正しいトラックで私を得た –

関連する問題