var numbers = new int[] { 1, 2, 3, 4, 5 };
var contacts = from c in context.Contacts
where c.ContactID == numbers.Max() | c.ContactID == numbers.FirstOrDefault()
select c;
foreach (var item in contacts) Console.WriteLine(item.ContactID); ;
Linq-to-Entitiesクエリは、最初にLinq式ツリーに変換され、次にObjectServicesによってコマンドツリーに変換されます。また、Linq-to-EntitiesクエリがLinq-to-Objectsクエリをネストしている場合、このネストされたクエリも式ツリーに変換されます。
a)ネストされたLinq-to-Objectsクエリの演算子は実際には実行されないと思いますが、代わりに特定のDB(またはおそらくObject Services)のデータプロバイダーはLinq-to-Objects演算子のロジックを適切なSQLに変換する方法を知っていますステートメント?
b)データプロバイダーは、一部のLinq-to-Objects演算子に対してのみ同等のSQLステートメントを作成する方法を知っていますか?
c)同様に、データプロバイダーは、Net Frameworkクラスライブラリの一部の非Linqメソッドに対してのみ同等のSQLステートメントを作成する方法を知っていますか?
ADAM MILLSへの返信:
1)あなたの返事に少し混乱しています。b)に返信して、SQL ServerのLinq2Entitiesデータプロバイダーが特定のLinq-to-Objects演算子をサポートしている場合、それを同等のSQLステートメントに変換しようとすることに同意し、c)に返信して、プロバイダーは特定の非Linqメソッドをサポートし、それを同等のSQLステートメントに変換します(サポートしていない場合は、例外をスローします)。しかし、a)の場合、 c)の場合とは正反対の応答をしたため、このプロバイダーはMax
同等のSqlステートメントに変換しようとせず、代わりにそれを実行して、クエリで戻り値を使用しますか?
2)とにかく、私はいくつかのSQLしか知らないので完全にはわかりませんが、上記のコードに対して生成されたSQLクエリを読むと、データプロバイダーは実際にはメソッドを実行しなかったようですが、代わりに最大値を返すはずnumbers.Max
であることがどういうわけかわかりました次に、生成されたSQLクエリにTSQLの組み込みMAX関数numbers.Max
への呼び出しを含めます。また、配列が保持するすべての値をSQLクエリに入れます。numbers
SELECT CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN '0X0X'
ELSE '0X1X'
END AS [C1],
[Extent1].[ContactID] AS [ContactID],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName],
[Extent1].[Title] AS [Title],
[Extent1].[AddDate] AS [AddDate],
[Extent1].[ModifiedDate] AS [ModifiedDate],
[Extent1].[RowVersion] AS [RowVersion],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[CustomerTypeID]
END AS [C2],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[InitialDate]
END AS [C3],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[PrimaryDesintation]
END AS [C4],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[SecondaryDestination]
END AS [C5],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[PrimaryActivity]
END AS [C6],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[SecondaryActivity]
END AS [C7],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[Notes]
END AS [C8],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[RowVersion]
END AS [C9],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[BirthDate]
END AS [C10],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[HeightInches]
END AS [C11],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[WeightPounds]
END AS [C12],
CASE
WHEN (([Project1].[C1] = 1)
AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[DietaryRestrictions]
END AS [C13]
FROM [dbo].[Contact] AS [Extent1]
LEFT OUTER JOIN (SELECT [Extent2].[ContactID] AS [ContactID],
[Extent2].[BirthDate] AS [BirthDate],
[Extent2].[HeightInches] AS [HeightInches],
[Extent2].[WeightPounds] AS [WeightPounds],
[Extent2].[DietaryRestrictions] AS [DietaryRestrictions],
[Extent3].[CustomerTypeID] AS [CustomerTypeID],
[Extent3].[InitialDate] AS [InitialDate],
[Extent3].[PrimaryDesintation] AS [PrimaryDesintation],
[Extent3].[SecondaryDestination] AS [SecondaryDestination],
[Extent3].[PrimaryActivity] AS [PrimaryActivity],
[Extent3].[SecondaryActivity] AS [SecondaryActivity],
[Extent3].[Notes] AS [Notes],
[Extent3].[RowVersion] AS [RowVersion],
cast(1 as bit) AS [C1]
FROM [dbo].[ContactPersonalInfo] AS [Extent2]
INNER JOIN [dbo].[Customers] AS [Extent3]
ON [Extent2].[ContactID] = [Extent3].[ContactID]) AS [Project1]
ON [Extent1].[ContactID] = [Project1].[ContactID]
LEFT OUTER JOIN (SELECT TOP (1) [c].[C1] AS [C1]
FROM (SELECT [UnionAll3].[C1] AS [C1]
FROM (SELECT [UnionAll2].[C1] AS [C1]
FROM (SELECT [UnionAll1].[C1] AS [C1]
FROM (SELECT 1 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable1]
UNION ALL
SELECT 2 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable2]) AS [UnionAll1]
UNION ALL
SELECT 3 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable3]) AS [UnionAll2]
UNION ALL
SELECT 4 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable4]) AS [UnionAll3]
UNION ALL
SELECT 5 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable5]) AS [c]) AS [Limit1]
ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [c].[C1] AS [C1]
FROM (SELECT [UnionAll7].[C1] AS [C1]
FROM (SELECT [UnionAll6].[C1] AS [C1]
FROM (SELECT [UnionAll5].[C1] AS [C1]
FROM (SELECT 1 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable6]
UNION ALL
SELECT 2 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable7]) AS [UnionAll5]
UNION ALL
SELECT 3 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable8]) AS [UnionAll6]
UNION ALL
SELECT 4 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable9]) AS [UnionAll7]
UNION ALL
SELECT 5 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable10]) AS [c]) AS [Limit2]
ON 1 = 1
CROSS JOIN (SELECT MAX([UnionAll12].[C1]) AS [A1]
FROM (SELECT [UnionAll11].[C1] AS [C1]
FROM (SELECT [UnionAll10].[C1] AS [C1]
FROM (SELECT [UnionAll9].[C1] AS [C1]
FROM (SELECT 1 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable11]
UNION ALL
SELECT 2 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable12]) AS [UnionAll9]
UNION ALL
SELECT 3 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable13]) AS [UnionAll10]
UNION ALL
SELECT 4 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable14]) AS [UnionAll11]
UNION ALL
SELECT 5 AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable15]) AS [UnionAll12]) AS [GroupBy1]
WHERE [Extent1].[ContactID] IN ([GroupBy1].[A1], (CASE
WHEN ([Limit1].[C1] IS NULL) THEN 0
ELSE [Limit2].[C1]
END))
これに基づいて、Linq2Entitiesプロバイダーが実際に非LinqおよびLinq-to-Objectメソッドを実行せず、代わりにそれらの一部に対して同等のSQLステートメントを作成する(および他の場合は例外をスローする)可能性はありますか?
2番目の編集:
わかりました、私はあなたが私に言ったことをしました:
b)の場合、Linq-to-Objects拡張メソッドを作成しました。
public static class TEST_CLASS
{
public static int Testing<TSource>(this IEnumerable<TSource> source)
{
Console.WriteLine("Testing Called"); // here I've put a breakpoint
return source.Count();
}
}
List<int> list = new List<int>() {1,2,3,4,5,6 };
var contact = (from c in context.Contacts
where c.ContactID == list.Testing()
select c).First();
コードをデバッグモードで実行すると、すぐに次の例外が発生します(したがって、デバッガーは例外をスローする前にTestingメソッドにステップインしません)。
System.NotSupportedException:LINQ to Entitiesは、メソッド'Int32 TestingInt32'メソッドを認識せず、このメソッドをストア式に変換できません。
c)非Linqメソッドを作成しました:
public class Another_TEST_CLASS
{
public static int Testing_Again()
{
Console.WriteLine("Testing_Again called");// here I've put a breakpoint
return 1000;
}
}
var contact = (from c in context.Contacts
where c.ContactID == Another_TEST_CLASS.Testing_Again()
select c).First();
コードをデバッグモードで実行すると、すぐに次の例外が発生します(したがって、デバッガーは例外をスローする前にTesting_Againメソッドにステップインしません)。
System.NotSupportedException:LINQ to Entitiesは、メソッド'Int32 Testing_Again()'メソッドを認識せず、このメソッドをストア式に変換できません。System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.Defaultで
前もって感謝します