Left Outer Join在LINQPad中工作(使用EF 4.3连接)但在应用程序中失败

时间:2012-07-06 16:51:20

标签: linq entity-framework-4 left-join linqpad

我有一个应用程序成功利用LINQ执行LEFT OUTER JOIN几个实例;但是,在一种情况下,它无法按预期工作。

在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字段赋值中的boolean引用headers变量(h.DepartmentId == null)中的join元素时,如下面的代码所示: / p>

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和相同的数据库)?

2 个答案:

答案 0 :(得分:2)

这是如何不在SQL中编写LINQ查询 - 思考然后transliterating into LINQ的典型示例。

使用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"
}

答案 1 :(得分:0)

似乎[t0] .DepartmentID(来自SalesOrderHeaders)可以为null。你的LEFT OUTER JOIN依赖于这个值。这最终将[t3] .DepartmentID与null(在某些情况下)进行比较。

您可能还需要使用JOIN中select的CASE语句。