LINQをうまく利用してLEFTOUTERJOINをいくつかのインスタンスで実行するアプリケーションがあります。ただし、1つのケースでは、期待どおりに機能しません。
LINQPadでのテスト(LINQ-to_SQLを使用)では、正しい結果が得られました。ただし、確実にLINQPadベータバージョン4.42.05に変更し、アプリケーションのDLLとweb.configファイルのconnectionStringを使用して正常に接続しました([接続の追加]ダイアログのとおり)。この場合も、LINQPadは適切な結果を返すことに成功し、TSQLで期待される左外部結合を明確に生成しますが、アプリケーションの同じコードは失敗します。
関数のデバッグ中に、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というメッセージが表示されます。エラー。次のコードと関連するTSQLの後に追加の説明を参照してください。この関係には、1つ以上の店舗を持つ顧客と、0以上の部門を持つwhoesストアが含まれることに注意してください。したがって、返されるレコードの中には部門がないものもあります(したがって、左外側の結合が必要です)。
次のコードはLINQPadで完全に機能します。
var model = (from h in SalesOrderHeaders
join c in Customers on h.CustomerId equals c.CustomerId
join s in Stores on h.StoreId equals s.StoreId
join d in Departments on h.DepartmentId equals d.DepartmentId into outer
from o in outer.DefaultIfEmpty()
select new
{
OrderId = h.SalesOrderHeaderId,
OrderDetailId = 1,
SalesOrderDate = h.SalesOrderDate,
DeliveryDateTime = h.DeliveryDateTime,
Customer = c.Customer,
Store = s.Store,
Department = (o.Department == null) ? "None" : o.Department,
FullDescription = "None",
Qty = 0,
UoM = "None",
}).OrderBy (m => m.OrderId);
以下のコードをアプリケーションで使用すると、失敗します。
var model = from h in headers
join c in customers on h.CustomerId equals c.CustomerId
join s in stores on h.StoreId equals s.StoreId
join d in departments on h.DepartmentId equals d.DepartmentId into outer
from o in outer.DefaultIfEmpty()
select new SalesOrderGridViewModel
{
OrderId = h.SalesOrderHeaderId,
OrderDetailId = 1,
SalesOrderDate = h.SalesOrderDate,
DeliveryDateTime = h.DeliveryDateTime,
Customer = c.Name,
Store = s.Name,
Department = (o.Name == null) ? "None" : o.Name,
FullDescription = "None",
Qty = 0,
UoM = "None",
};
ただし、次のコードのように、結果の部門フィールドの割り当てのブール値がヘッダー変数(h.DepartmentId == null)のjoin要素を参照するようにアプリケーションのコードを変更すると、次のようになります。
var model = from h in headers
join c in customers on h.CustomerId equals c.CustomerId
join s in stores on h.StoreId equals s.StoreId
join d in departments on h.DepartmentId equals d.DepartmentId into outer
from o in outer.DefaultIfEmpty()
select new SalesOrderGridViewModel
{
OrderId = h.SalesOrderHeaderId,
OrderDetailId = 1,
SalesOrderDate = h.SalesOrderDate,
DeliveryDateTime = h.DeliveryDateTime,
Customer = c.Name,
Store = s.Name,
Department = (h.DepartmentId == null) ? "None" : o.Name,
FullDescription = "None",
Qty = 0,
UoM = "None",
};
期待される結果が返されます。
興味深いことに、元のコードから最初に生成されたTSQLの微妙な違いは次のとおりです。
SELECT [t4].[SalesOrderHeaderId] AS [OrderId], [t4].[SalesOrderDate],
[t4].[DeliveryDateTime], [t4].[Customer], [t4].[Store],
[t4].[value] AS [Department]
FROM (
SELECT [t0].[SalesOrderHeaderId], [t0].[SalesOrderDate],
[t0].[DeliveryDateTime], [t1].[Customer], [t2].[Store],
(CASE
WHEN [t3].[Department] IS NOT NULL THEN [t3].[Department]
ELSE CONVERT(NVarChar(50),@p0)
END) AS [value]
FROM [SalesOrderHeaders] AS [t0]
INNER JOIN [Customers] AS [t1] ON [t0].[CustomerId] = [t1].[CustomerId]
INNER JOIN [Stores] AS [t2] ON [t0].[StoreId] = ([t2].[StoreId])
LEFT OUTER JOIN [Departments] AS [t3]
ON [t0].[DepartmentId] = ([t3].[DepartmentId])) AS [t4]
ORDER BY [t4].[SalesOrderHeaderId]
そして、元のヘッダーテーブルのDepartmentIdの値をテストするためにブール値が変更された改訂コード([t3]。[Department]と[t0]。[DepartmentId])から、解決策のように見えます。
SELECT [t4].[SalesOrderHeaderId] AS [OrderId], [t4].[SalesOrderDate],
[t4].[DeliveryDateTime], [t4].[Customer], [t4].[Store],
[t4].[value] AS [Department]
FROM (
SELECT [t0].[SalesOrderHeaderId], [t0].[SalesOrderDate],
[t0].[DeliveryDateTime], [t1].[Customer], [t2].[Store],
(CASE
WHEN [t0].[DepartmentId] IS NOT NULL THEN [t3].[Department]
ELSE CONVERT(NVarChar(50),@p0)
END) AS [value]
FROM [SalesOrderHeaders] AS [t0]
INNER JOIN [Customers] AS [t1] ON [t0].[CustomerId] = [t1].[CustomerId]
INNER JOIN [Stores] AS [t2] ON [t0].[StoreId] = ([t2].[StoreId])
LEFT OUTER JOIN [Departments] AS [t3]
ON [t0].[DepartmentId] = ([t3].[DepartmentId])) AS [t4]
ORDER BY [t4].[SalesOrderHeaderId]
私はこれを機能させる方法を見つけましたが、LINQPadでも、アプリケーション全体に散在する他の多数のLINQクエリでも正常に機能するため、この1つの場所での元の形式での失敗が懸念されます。
最終的に、左外部結合の戻り値をテストすると、アプリケーションで失敗するように見えます。ただし、これは多くの本や記事で文書化された慣行です。だから私の最後の質問は、なぜこれが起こるのか、そして/またはそれがLINQPadで(アプリケーションDLLを使用して同じDBに対して)どのように機能するのかについて誰かが洞察を持っているかどうかです。