4

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 を取得します: Method 'System.DateTime RiyadhTimeFromUtc(System.DateTime)' has no supported translation to SQL.

同一のコードが拡張メソッドにない場合、コンパイラは喜んでSQLに変換したため、これは明らかにゴミです。

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

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

4

2 に答える 2

9

式ツリーの観点から考える必要があります。これは、Linq-to-SQL がクエリを解析して SQL に変換する方法です。

ツリーを調べると、DateTimeオブジェクトが表示され、その上で呼び出されたメソッドがサポートされているメソッド ( 、 など) の 1 つであるかどうかがチェックされるAddためAddHours、メソッドを直接使用すると問題なく動作します。

他の拡張メソッドを使用する場合、そのメソッドの本体に関する情報は式ツリーになく、IL に隠されているため、そのメソッドの内部に移動してその動作を確認することはできません。したがって、拡張メソッドの内容がサポートされているかどうかは問題ではありません。Linq-to-SQL は内容が何であるかを判断できないためです。

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


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

これは、Linq の残念な制限の 1 つです。多くのものと同様に、これはやや漏れやすい抽象化であり、さまざまなソースに共通の構文を提供しますが、ソースのプロバイダーがサポートできる/サポートする操作についてさまざまな制限と制限があります (たとえば、これは Linq-to で完全に正常に機能します)。 -実行するために式ツリーを変換する必要がないため、オブジェクト)。

于 2009-03-04T07:55:43.107 に答える
4

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に変換しますか?詳細については、このディスカッションを参照してください。

于 2009-03-04T07:58:31.210 に答える