左外连接在LINQPad中工作(使用EF 4.3连接),但在应用程序中失败

左外连接在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中生成了预期的左外部联接,但应用程序中的相同代码失败了 在调试函数时,我得到“对象引用

我有一个应用程序,它成功地利用LINQ执行多个实例的左外连接;然而,在一个案例中,它没有像预期的那样工作

在LINQPad中测试(使用LINQ-to_SQL)产生了正确的结果;但是,为了确保更改为LINQPad beta版本4.42.05,并使用应用程序的DLL及其web.config文件中的connectionString成功连接(根据添加连接对话框)。同样,LINQPad成功地返回了正确的结果,并在TSQL中生成了预期的左外部联接,但应用程序中的相同代码失败了

在调试函数时,我得到“对象引用未设置为对象的实例。”错误。请参阅以下代码和相关TSQL之后的其他说明。注意,这种关系涉及到拥有一个或多个门店的客户,以及门店没有或多个部门的客户。因此,一些返回的记录将没有部门(因此需要左外部联接)

以下代码在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",
        };
但是,当我更改应用程序中的代码,以便结果的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
属性吗?