左外连接在LINQPad中工作(使用EF 4.3连接),但在应用程序中失败
我有一个应用程序,它成功地利用LINQ执行多个实例的左外连接;然而,在一个案例中,它没有像预期的那样工作 在LINQPad中测试(使用LINQ-to_SQL)产生了正确的结果;但是,为了确保更改为LINQPad beta版本4.42.05,并使用应用程序的DLL及其web.config文件中的connectionString成功连接(根据添加连接对话框)。同样,LINQPad成功地返回了正确的结果,并在TSQL中生成了预期的左外部联接,但应用程序中的相同代码失败了 在调试函数时,我得到“对象引用未设置为对象的实例。”错误。请参阅以下代码和相关TSQL之后的其他说明。注意,这种关系涉及到拥有一个或多个门店的客户,以及门店没有或多个部门的客户。因此,一些返回的记录将没有部门(因此需要左外部联接) 以下代码在LINQPad中非常有效:左外连接在LINQPad中工作(使用EF 4.3连接),但在应用程序中失败,linq,entity-framework-4,left-join,linqpad,Linq,Entity Framework 4,Left Join,Linqpad,我有一个应用程序,它成功地利用LINQ执行多个实例的左外连接;然而,在一个案例中,它没有像预期的那样工作 在LINQPad中测试(使用LINQ-to_SQL)产生了正确的结果;但是,为了确保更改为LINQPad beta版本4.42.05,并使用应用程序的DLL及其web.config文件中的connectionString成功连接(根据添加连接对话框)。同样,LINQPad成功地返回了正确的结果,并在TSQL中生成了预期的左外部联接,但应用程序中的相同代码失败了 在调试函数时,我得到“对象引用
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",
};
但是,当我更改应用程序中的代码,以便结果的department字段赋值中的布尔值引用headers变量(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查询中成功地工作,所以它在这个位置的原始形式失败让我担心
最终,当我测试左外部联接的返回值时,它在应用程序中似乎失败了。然而,这是许多书籍和文章中记载的实践。因此,我的最后一个问题是,是否有人了解这种情况发生的原因和/或它如何在LINQPad中工作(使用应用程序DLL并针对相同的数据库)?似乎[t0]。部门ID(来自SalesOrderHeaders)可以为空。左侧外部联接依赖于此值。最后将[t3].DepartmentID与null进行比较(在某些情况下)
您可能还需要在连接中使用select中的CASE语句。这是一个典型的示例,说明了如何不编写LINQ查询—先用SQL思考,然后再编写 使用LINQ,您可以完全避免连接,并按如下方式制定查询:
from h in SalesOrderHeaders
orderby h.OrderId
select new
{
OrderId = h.SalesOrderHeaderId,
OrderDetailId = 1,
SalesOrderDate = h.SalesOrderDate,
DeliveryDateTime = h.DeliveryDateTime,
c.Customer.Customer,
s.Store.Store,
Department = (h.Department == null) ? "None" : h.Department.Department,
FullDescription = "None",
Qty = 0,
UoM = "None"
}
在
model
或类似设备上调用ToList()
时,是否会出现错误?headers
是上下文的DbSet
属性吗?