5

以下は、2つのケースのLINQ to SQLクエリで生成されたC#コードとSQ​​Lです。

ケース1

using (JulianDataContext dc = new JulianDataContext(this.CurrentConnectionString))
{
#if DEBUG
    dc.Log = new DebugTextWriter();
#endif

    IEnumerable<UserNewsfeedDeliveryTime> temp = dc.UserNewsfeedDeliveryTimes.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);

    ids = temp.Select(p => p.Id).ToList();
}

SELECT [t0].[Id], [t0].[NewsfeedEmailPeriodicity], [t0].[LastSentNewsfeedEmail], [t0].[NextNewsfeedDelivery]
FROM [dbo].[UserNewsfeedDeliveryTimes] AS [t0]
WHERE ([t0].[NewsfeedEmailPeriodicity] > @p0) AND (@p1 >= CONVERT(DATE, [t0].[NextNewsfeedDelivery]))
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [0]
-- @p1: Input DateTime (Size = -1; Prec = 0; Scale = 0) [15-11-2012 00:00:00]

ケース2

using (JulianDataContext dc = new JulianDataContext(this.CurrentConnectionString))
{
#if DEBUG
            dc.Log = new DebugTextWriter();
#endif
    IEnumerable<UserNewsfeedDeliveryTime> temp = dc.GetTable<UserNewsfeedDeliveryTime>();

    temp = temp.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);

    ids = temp.Select(p => p.Id).ToList();
}
SELECT [t0].[Id], [t0].[NewsfeedEmailPeriodicity], [t0].[LastSentNewsfeedEmail], [t0].[NextNewsfeedDelivery]
FROM [dbo].[UserNewsfeedDeliveryTimes] AS [t0]

違い

これら2つのlinqクエリの違い:

dc.UserNewsfeedDeliveryTimes

dc.GetTable <UserNewsfeedDeliveryTime>()

なんで?ケース2の場合、LINQ to SQLがデータベースからすべてのデータを取得し、メモリ内のすべてのオブジェクトをフィルタリングしてクエリを終了している可能性がありますか?

もしそうなら、どうすればこれを汎用的に保ちながら、すべてのT-SQLを強制的に生成させることができますか?

解決

どちらの答えも正解ですが、どちらかを選択する必要がありました。ごめんなさい。この場合、IQueryable(IEnumerableから継承)を使用するように変更したので、次の行にこれを追加することも興味深いと思います。

temp = temp.Where(u => u.NewsfeedEmailPeriodicity> 0 && DateTime.Today> = u.NextNewsfeedDelivery.Value.Date);

2つのオーバーロードメソッドがありました。1つはIQueryableインターフェイスから、もう1つはIEnumerableインターフェイスからです。

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

そのため、述語を明示的にExpression> predicateに変換する必要がありました。そうしないと、コンパイル時にIEnumerableインターフェイスメソッドが取得され、間違えなければ、T-SQLでは不可能であるという動的SQL例外が発生します。生成されます。

4

2 に答える 2

2

私の理解では、保持IEnumerableしている元のクエリ情報は変換されませんIQueryable。キャストの時点で、キャストがクエリへの変更を凍結するかのようIQueryableです。MSDN を見ると、以下がIQueryable継承されていることがわかりIEnumerableます。

http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

したがって、この動作が見られます。IQueryableクエリが. _ _IEnumerable

最初の例でwhereは、元のクエリが含まれています。でselectはないため、クエリが生成されます。

2 番目の例では、テーブル自体をIEnumerable. これに対する変更は、元のクエリに加えてメモリ内で行われます。

考えてみると、 のIEnumerableバージョンは、キャストと継承のしくみによりwhere、 の元のデータを変換できなくなります。IQueryable

遅延読み込みと LINQ のしくみも考慮すると、これは理にかなっているように思えます。私にとっては、パフォーマンスの悪いコードが生成される可能性があるため、非常に厄介です。

于 2012-11-16T18:48:40.200 に答える
2

IEnumerableの代わりにIQueryableを使用してみてください。

奇妙なことに、私の例では逆の結果が得られます。つまり、IEnumerable を使用すると、ケース 1 は高速に動作し、ケース 2 はすべてのデータを取得します。しかし、IQueryable を使用すると問題が解決します。

于 2012-11-16T11:18:55.393 に答える