根据第一个表列值(Lambda查询)连接表

时间:2018-04-16 11:30:25

标签: c# linq left-join inner-join

我有3张桌子:

  • 交付tbl
  • InternalDriver tbl
  • ExternalDriver tbl

enter image description here

enter image description here

enter image description here

现在,如何从Delivery表中获取一个集合,该集合将从仅执行一个lambda查询的其他表中获取DriverNames

需要考虑的事项:

  • DriverTypeInternal时,它应该从DriverNames表格中获取InternalDriver

  • DriverTypeExternal时,它应该从DriverNames表格中获取ExternalDriver

3 个答案:

答案 0 :(得分:2)

您可以单独加入两种类型的驱动程序,然后在可接受的情况下连接结果:

var deliveries = new Delivery[] { };
var internalDrivers = new Driver[] { /*...*/ };
var externalDrivers = new Driver[] { /*...*/ };

var deliveryModels = deliveries.Where(dl => dl.DriverType == "Internal")
    .Join(internalDrivers, delivery => delivery.DriverId, driver => driver.Id,
        (dl, dr) => new DeliveryModel {DeliveryId = dl.Id, DriverName = dr.DriverName})
    .Concat(deliveries.Where(dl => dl.DriverType == "External")
        .Join(externalDrivers, delivery => delivery.DriverId, driver => driver.Id,
            (dl, dr) => new DeliveryModel {DeliveryId = dl.Id, DriverName = dr.DriverName}));

//....
public class  DeliveryModel
{
    public int DeliveryId { get; set; }
    public string DriverName { get; set; }
}

或者,为避免连接,您可以使用GroupJoin两次使用DriverId和DriverType的组合键来连接内部和外部驱动程序,并查看匹配的内容:

var deliveryModels = deliveries.GroupJoin(internalDrivers,
        delivery => (delivery.DriverType, delivery.DriverId), driver => ("Internal", driver.Id),
        (dl, dr) => (dl, dr))
    .GroupJoin(externalDrivers,
        internalDriversJoin => (internalDriversJoin.dl.DriverType, internalDriversJoin.dl.DriverId),
        extDr => ("External", extDr.Id),
        (internalJoinResult, dr) => new DeliveryModel
        {
            DeliveryId = internalJoinResult.dl.Id,
            DriverName = (internalJoinResult.dr.FirstOrDefault() ?? dr?.FirstOrDefault())?.DriverName
        });

我不知道在第二个查询中会生成哪个SQL(我希望有两个LEFT JOIN,但不确定)以及性能如何:它可能比第一个查询更好,或者可能更糟糕 - 在大数据场景中使用之前测试一下......

如果对于LINQ to对象,我会使用第一个查询 - 它肯定更简单,并且应该更快,因为在内存中创建的对象更少。

答案 1 :(得分:0)

我认为你可以这样做:

var d = from del in db.deliveries
        join intdrv in db.internalDrivers on new { t = del.DriverType, i = del.DriverId } 
            equals new { t = "Internal", i = intdrv.DriverId } into tdi
        from di in tdi.DefaultIfEmpty()
        join extdrv in db.externalDrivers on new { t = del.DriverType, i = del.DriverId }
            equals new { t = "External", i = extdrv.DriverId } into tde
        from de in tde.DefaultIfEmpty()
        where (di ?? de) != null
        select new
        {
            DeliveryId = del.Id,
            DriverName = (di ?? de).DriverName
        };

基本上它会执行两个左连接,每个表一个,然后使用空合并运算符来选择第一个非空结果。在哪里确保找到其中一个。

答案 2 :(得分:-1)

我没考试。但你可以尝试我的解决方案。希望能帮忙,我的朋友:

var data = from u in Delivery
             select new
             {
                Id = u.Id,
                DriverName = u.DriverType == "Internal" ?  u.InternalDriver.DriverName : u.ExternalDriver.DriverName;                    
              }