エンティティを介していくつかのLINQをいじくり回していて、奇妙な結果が得られているので、説明を求めています...
次のLINQクエリが与えられると、
// Sample # 1
IEnumerable<GroupInformation> groupingInfo;
groupingInfo = from a in context.AccountingTransaction
group a by a.Type into grp
select new GroupInformation()
{
GroupName = grp.Key,
GroupCount = grp.Count()
};
次のSQLクエリを取得します(SQLプロファイラーから取得)。
SELECT
1 AS [C1],
[GroupBy1].[K1] AS [Type],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Extent1].[Type] AS [K1],
COUNT(1) AS [A1]
FROM [dbo].[AccountingTransaction] AS [Extent1]
GROUP BY [Extent1].[Type]
) AS [GroupBy1]
ここまでは順調ですね。
LINQクエリを次のように変更した場合:
// Sample # 2
groupingInfo = context.AccountingTransaction.
GroupBy(a => a.Type).
Select(grp => new GroupInformation()
{
GroupName = grp.Key,
GroupCount = grp.Count()
});
まったく同じSQLクエリになります。私には理にかなっています。
ここに興味深い部分があります... LINQクエリを次のように変更すると:
// Sample # 3
IEnumerable<AccountingTransaction> accounts;
IEnumerable<IGrouping<object, AccountingTransaction>> groups;
IEnumerable<GroupInformation> groupingInfo;
accounts = context.AccountingTransaction;
groups = accounts.GroupBy(a => a.Type);
groupingInfo = groups.Select(grp => new GroupInformation()
{
GroupName = grp.Key,
GroupCount = grp.Count()
});
次のSQLが実行されます(実際のクエリからいくつかのフィールドを削除しましたが、テーブルのすべてのフィールド(〜15フィールド)がクエリに2回含まれていました):
SELECT
[Project2].[C1] AS [C1],
[Project2].[Type] AS [Type],
[Project2].[C2] AS [C2],
[Project2].[Id] AS [Id],
[Project2].[TimeStamp] AS [TimeStamp],
-- <snip>
FROM ( SELECT
[Distinct1].[Type] AS [Type],
1 AS [C1],
[Extent2].[Id] AS [Id],
[Extent2].[TimeStamp] AS [TimeStamp],
-- <snip>
CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
FROM (SELECT DISTINCT
[Extent1].[Type] AS [Type]
FROM [dbo].[AccountingTransaction] AS [Extent1] ) AS [Distinct1]
LEFT OUTER JOIN [dbo].[AccountingTransaction] AS [Extent2] ON [Distinct1].[Type] = [Extent2].[Type]
) AS [Project2]
ORDER BY [Project2].[Type] ASC, [Project2].[C2] ASC
生成されるSQLが非常に異なるのはなぜですか?結局のところ、まったく同じコードが実行されます。サンプル#3が中間変数を使用して同じジョブを実行しているだけです。
また、私がそうする場合:
Console.WriteLine(groupingInfo.ToString());
サンプル#1とサンプル#2の場合、SQLプロファイラーによってキャプチャされたものとまったく同じクエリを取得しますが、サンプル#3の場合、次のようになります。
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Linq.IGrouping`2[System.Object,TestLinq.AccountingTransaction],TestLinq.GroupInformation]
違いはなんですか?LINQクエリを複数の命令に分割した場合、LINQによって生成されたSQLクエリを取得できないのはなぜですか?
究極の目標は、実行時にクエリ(Where、OrderByなど)に演算子を追加できるようにすることです。
ところで、私はEF4.0とEF6.0でこの動作を見てきました。
ご協力ありがとうございました。
その理由は、3回目の試行で、Linq-To-Objects(および)を使用してクエリが呼び出されるように参照しaccounts
ているためです。IEnumerable<AccountingTransaction>
Enumerable.GroupBy
Enumerable.Select
一方、1回目と2回目の試行では、への参照AccountingTransaction
はとして保持されIQueryable<AccountingTransaction>
、クエリはLinq-To-Entitiesを使用して実行され、適切なSQLステートメントに変換されます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加