2

これは矛盾しているように見えますが、おそらく明らかな何かが欠けているだけです。基本クエリは次のとおりです。

var events = db.tbl_special_events.Where(x => x.TimeStamp >= startDate);

次のコード ブロックを実行すると、明らかな矛盾が生じます。

int c1 = 0;
foreach (var e in events)
{
    if (e.TimeStamp.DayOfWeek.ToString() == "Tuesday") c1++;
}

int c2 = events.Where(e => e.TimeStamp.DayOfWeek.ToString() == "Tuesday").Count();

それが実行された後、c1 は 1832 ですが、c2 は 0 です。

4

2 に答える 2

2

このテストを再作成したところ、DateTime 関数に直接関係している可能性があることがわかりました。

生成されるクエリ:

exec sp_executesql N'SELECT [t0].[User_ID], [t0].[Email], [t0].[Password], [t0].[BrandID], [t0].[CustomerID], [t0].[Created], [t0].[EndDate], [t0].[AccountStatusID], [t0].[Verified], [t0].[ResetPasswordFailCount], [t0].[ResetPasswordLocked]
FROM [dbo].[User] AS [t0]
WHERE ((CONVERT(NVarChar,CONVERT(Int,(DATEPART(dw, [t0].[Created]) + (@@DATEFIRST) + 6) % 7))) = @p0) AND ([t0].[BrandID] = @p1)',N'@p0 nvarchar(4000),@p1 int',@p0=N'Tuesday',@p1=3

@p0=N'Tuesday' の場所に注意してください

IQueryable と IEnumerable は、IEnumerable が実際の .net オブジェクトを表すという点で異なることに注意してください。IQueryable は、式をデータベースのクエリに使用される実際の SQL ステートメントに変換します。したがって、その式で指定した値は実際にデータベースに送信されます。

一致がないため、0 の結果が返されます。これは、SQL の日付変換が「火曜日」ではなく 2 を返すためです。LINQ WHERE 句で Tuesday を 2 に置き換えると、これをテストできます。実際に機能します。結果が使用可能な .net オブジェクトに正常にマップされ、DateTime.DayOfWeek から "Tuesday" への変換が適切に機能するため、これは列挙後に機能します。

于 2013-02-27T20:53:21.610 に答える
1

あなたのカウントは列挙さIQueryable<Event>れたeインスタンスです。したがって、一部の操作は SQL に変換できないため、機能しない可能性があります [編集: または無意味な SQL に変換されます]。

Where句が確実に機能するようにするには、そのAsEnumerable()前にを追加します。これにより、 が に変換IQueryable<Event>され、IEnumerable<Event>この時点で SQL の生成を停止する必要があることが linq プロバイダーに通知されます。

したがって、次のステートメントは正しい結果を提供するはずです。

int c2 = events.AsEnumerable()
    .Where(e => e.TimeStamp.DayOfWeek.ToString() == "Tuesday")
    .Count();

変換できない実際のコードは、SQL で問題を引き起こしますe.TimeStamp.DayOfWeek.ToString()

System.Data.Objects.SqlClient.SqlFunctionsまたは、 ( doc here ) クラスを使用して、linq プロバイダーが SQL で何をすべきかを示唆することもできます。

編集

@Servy が指摘したように、これは Linq to SQL の質問です。ただし、問題は非常に一般的であるため、回答を残して削除しません。

OPをもう一度見ると、ゲーム全体に別の変数がある可能性があります...遅延読み込み。

foreach ループでは、TimeStamp が遅延ロードされます。count クエリでは、プロバイダーは SQL クエリを構築しようとしますが、この構築中にToString(問題があることが知られている)処理できず、 とはe.TimeStamp.DayOfWeek.ToString()異なるものに評価される可能性があり"Tuesday"ます。

これAsEnumerable()により、プロバイダーは SQL の生成を強制的に停止するため、e.TimeStamp再度遅延読み込みが行われます。

何が起こっているのかを正確に把握する唯一の方法は、DB でトレース ツール (SQL Server Profiler など) を使用して、サーバーで実行されたクエリ (複数可) を実際に確認することです。

編集 2

@Sinaestheticの答えに基づいて構築すると、0が返される理由は、クエリがfalseを返すものと比較しようとする"4"ため"Tuesday"、正しい結果はfalse.

実行することでテスト可能

select ((CONVERT(NVarChar,CONVERT(Int,(DATEPART(dw, getdate()) + (@@DATEFIRST) + 6) % 7))))

DBに対して。

ただし、これは、生成する SQL を決定するのはプロバイダー次第であることも示しています。また、どのステートメントをサポートし、どのステートメントをサポートしないかを決定するのは、プロバイダー次第です。

また、SQL 生成プロセスを停止するために を使用AsEnumerableすると、クエリのセマンティック評価に影響を与える可能性があることも示しています。

于 2013-02-27T15:11:50.977 に答える