两个表左深外连接

时间:2015-04-03 21:19:19

标签: 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上查看了与我类似的其他问题,但我无法弄清楚与我的查询和发布的解决方案有什么不同。

有人可以帮我弄清楚为什么我得到空引用异常以及我需要采取哪些不同的做法?

4 个答案:

答案 0 :(得分:2)

根据MSDN

  

reference和nullable类型的默认值为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();
    }
}

答案 1 :(得分:0)

您应该检查您选择的新{...}值是否为空

像:

 select new
 {
     table1 = cec,
     table2 = ceclrp,
     table3 = lrp,
     table4 = (ecService == null ? string.Empty : ecService),
     table5 = (ecServiceEntitlement == null ? string.Empty : ecServiceEntitlement),
 }).AsNoTracking();

答案 2 :(得分:0)

这可能是问题所在。

join cecse in _myContext.table5s on ecService.table4ID equals cecse.table4ID into cecseGroup

ecService == null时,ecService .table4ID会导致Null reference exception

你能不能试试呢。

join cecse in _myContext.table5s on (ecService == null?  0 : ecService.table4ID) equals cecse.table4ID into cecseGroup

您可以将0更改为_myContext.table4s.table4ID中未使用的任何整数值。所以你的查询看起来像这样。

(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 == null?  0 : 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();

答案 3 :(得分:0)

我只是将cecse变量扩展为左外连接。就像我们在原始SQL中完成它一样。

(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()
 from cecse in _myContext.table5s.DefaultIfEmpty()        // <---- here
 from ecServiceEntitlement in cecseGroup.DefaultIfEmpty()
 where cec.ClientKey == clientKey
    && ecService.table4ID equals cecse.table4ID           // <---- here
 select new
 {
     table1 = cec,
     table2 = ceclrp,
     table3 = lrp,
     table4 = ecService,
     table5 = ecServiceEntitlement,
 }).AsNoTracking();
相关问题