c# - 两个表深左外连接

标签 c# sql-server entity-framework linq-to-entities left-join

我有以下查询,并且收到空引用异常:

(from cec in _myContext.table1s
 join ceclrp in _myContext.table2s on cec.table1ID equals ceclrp.table1ID
 join lrp in _myContext.table3s on ceclrp.table3ID equals lrp.table3ID
 join cecs in _myContext.table4s on cec.table1ID equals cecs.table1ID into cecsGroup
 from ecService in cecsGroup.DefaultIfEmpty()
 join cecse in _myContext.table5s on ecService.table4ID equals cecse.table4ID into cecseGroup
 from ecServiceEntitlement in cecseGroup.DefaultIfEmpty()
 where cec.ClientKey == clientKey
 select new
 {
     table1 = cec,
     table2 = ceclrp,
     table3 = lrp,
     table4 = ecService,
     table5 = ecServiceEntitlement,
 }).AsNoTracking();

表 1、2 和 3 记录是必需的表。然而表4记录是可选的。如果有表 4 记录,则可以有可选的表 5 记录。

但是,当没有表 4 或表 5 记录时,我收到空引用异常。

我在 StackOverflow 上查看了与我的问题类似的其他问题,但我无法弄清楚我的查询和发布的解决方案有何不同。

有人可以帮我弄清楚为什么我会收到空​​引用异常以及我需要采取哪些不同的措施吗?

最佳答案

根据MSDN ,

The default value for reference and nullable types is null.

对于多个 LEFT JOIN ,我们可以处理null通过传递值defaultValue对于DefaultIfEmpty()扩展方法。当我传递默认构造函数 new Driver() 时,以下示例代码有效,如果 defaultValue 则抛出异常已删除。

在这里,我创建了三个具有匹配记录的模型 ( Dealer, Model and Customer ) 和两个具有可选记录的模型 ( Driver, DriverAddress )。与OP场景相同。

因此,传递第一个 LEFT JOIN 的默认值可以解决您的问题。

public class Dealer
{
    public int DealerId { get; set; }
    public string Name { get; set; }
}

public class Model
{
    public int ModelId { get; set; }
    public string Name { get; set; }
    public Dealer Dealer { get; set; }
}

public class Customer
{
    public int CustomerId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Model Model { get; set; }
}

public class Driver
{
    public int DriverId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Customer Customer { get; set; }
}

public class DriverAddress
{
    public int DriverAddressId { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string Zip { get; set; }
    public Driver Driver { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        var honda = new Dealer { DealerId = 1, Name = "Honda" };
        var ford = new Dealer { DealerId = 2, Name = "Ford" };
        var toyoto = new Dealer { DealerId = 3, Name = "Toyoto" };
        var volkswagen = new Dealer { DealerId = 4, Name = "Volkswagen" };
        var chevrolet = new Dealer { DealerId = 5, Name = "Chevrolet" };

        var civic = new Model { ModelId = 1, Name = "Civic", Dealer = honda };
        var fiesta = new Model { ModelId = 2, Name = "Fiesta", Dealer = ford };
        var corolla = new Model { ModelId = 3, Name = "Corolla", Dealer = toyoto };
        var passat = new Model { ModelId = 4, Name = "Passat", Dealer = volkswagen };
        var cruze = new Model { ModelId = 5, Name = "Cruze", Dealer = chevrolet };

        var magnus = new Customer { CustomerId = 1, FirstName = "Magnus", LastName = "Hedlund", Model = civic };
        var terry = new Customer { CustomerId = 2, FirstName = "Terry", LastName = "Adams", Model = fiesta };
        var charlotte = new Customer { CustomerId = 3, FirstName = "Charlotte", LastName = "Weiss", Model = corolla };
        var john = new Customer { CustomerId = 4, FirstName = "John", LastName = "Miller", Model = passat };
        var arlene = new Customer { CustomerId = 5, FirstName = "Arlene", LastName = "Huff", Model = cruze };

        var driver1 = new Driver { DriverId = 1, FirstName = "Fadi", LastName = "Fakhouri", Customer = magnus };
        var driver2 = new Driver { DriverId = 2, FirstName = "Hanying", LastName = "Feng", Customer = terry };
        var driver3 = new Driver { DriverId = 3, FirstName = "Cesar", LastName = "Garcia", Customer = charlotte };
        var driver4 = new Driver { DriverId = 4, FirstName = "Lint", LastName = "Tucker", Customer = magnus };
        var driver5 = new Driver { DriverId = 5, FirstName = "Robert", LastName = "Thomas", Customer = arlene };
        var driver6 = new Driver { DriverId = 6, FirstName = "David", LastName = "Adams", Customer = charlotte };

        var driver1Address = new DriverAddress { DriverAddressId = 1, AddressLine1 = "Main St", City = "Minnehaha", Zip = "57105", Driver = driver1 };
        var driver2Address = new DriverAddress { DriverAddressId = 2, AddressLine1 = "State St", City = "Los Angeles", Zip = "90034", Driver = driver2 };
        var driver3Address = new DriverAddress { DriverAddressId = 3, AddressLine1 = "Ralph St", City = "Winnebago", Zip = "61109", Driver = driver4 };

        List<Dealer> lstDealers = new List<Dealer> { honda, ford, toyoto, volkswagen, chevrolet };
        List<Model> lstModels = new List<Model> { civic, fiesta, corolla, passat, cruze };
        List<Customer> lstCustomers = new List<Customer> { magnus, terry, charlotte, john, arlene };
        List<Driver> lstDrivers = new List<Driver> { driver1, driver2, driver3, driver4, driver5, driver6 };
        List<DriverAddress> lstDriverAddress = new List<DriverAddress> { driver1Address, driver2Address, driver3Address };

        var result = from dealer in lstDealers
                     join model in lstModels on dealer.DealerId equals model.Dealer.DealerId
                     join customer in lstCustomers on model.ModelId equals customer.Model.ModelId
                     join driver in lstDrivers on customer.CustomerId equals driver.Customer.CustomerId into customerDriverGroup
                     from customerDriver in customerDriverGroup.DefaultIfEmpty(new Driver()) //defaultValue the empty constructor passed here
                     join address in lstDriverAddress on customerDriver.DriverId equals address.Driver.DriverId into driverAddressGroup
                     from driverAddress in driverAddressGroup.DefaultIfEmpty()
                     select new
                     {
                         Dealer = dealer,
                         Model = model,
                         Customer = customer,
                         Driver = customerDriver,
                         DriverAddress = driverAddress
                     };

        foreach (var v in result)
        {
            Console.WriteLine("{0,-15}{1,-15}{2,-15}{3,-15}{4}", v.Dealer.Name + ":",
                v.Model.Name + ":", v.Customer.FirstName + ":", v.Driver == null ? String.Empty : v.Driver.FirstName
                + ":", v.DriverAddress == null ? string.Empty : v.DriverAddress.City);
        }
        Console.Read();
    }
}

关于c# - 两个表深左外连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29439845/

相关文章:

c# - asp.Net 如何将数据保存到 Controller 中的联结表

c# - 客户端使用 OpenPop 进行身份验证时,密码是否需要编码?

c# - 使用 OLEDB 连接字符串打开 MS Access 并且无权创建 .ldb 锁定文件

sql - 为什么 SQL Server 不支持无符号数据类型?

sql - 了解 SQL 中的 NOT EXISTS

c# - 接受过滤条件和要过滤的属性的通用 Linq to Entities 过滤方法

c# - 如何针对列的 md5 进行 EntityFramework 查询

c# - 使用 C# 更改 WPF 列表框 SelectedItem 文本颜色和突出显示/背景颜色

c# - 在 javascript 函数中添加 <%%> 将在页面加载时强制执行?

sql-server - 根据 SQL Server 2005 中的当前月份查找列的总和