Linq左连接返回内连接

时间:2018-02-19 17:22:01

标签: c# sql-server entity-framework linq

我正在尝试使用Linq在C#中执行外连接,指导我的人一直说我不应该尝试进行外连接,这不是一个真正的答案。

我从其他主题得到的是,我需要.DefaultIfEmpty()我可能没有记录。

我首先尝试了可能缺少信息的行,然后将其添加到每一行,以查看是否存在问题。

每次运行此操作时,我只获得内部联接记录。除了不包括我的数据库中只有前两个表中的信息的两个记录之外,它的效果很好。

var sqlQuery =
from s in ctx.Suppliers
from sp in ctx.SupplierParts
    .Where(sp => sp.SupplierID == s.SupplierID)
    .DefaultIfEmpty()
from sm in ctx.SupplierManufacturerRelations
    .Where(sm => sm.SupplierPNID == sp.SupplierPNID)
    .DefaultIfEmpty()
from mp in ctx.ManufacturerParts
    .Where(mp => mp.MfgPNID.Equals(sm.MfgPNID))
    .DefaultIfEmpty()
from m in ctx.Manufacturers
    .Where(m => m.ManufacturerID.Equals(mp.ManufacturerID))
    .DefaultIfEmpty()
from im in ctx.ItemMasters
    .Where(im => im.PreID == mp.PreID)
    .Where(im => im.PartNumber == mp.PartNumber)
    .DefaultIfEmpty()
from c in ctx.ComponentClasses
    .Where(c => c.CCID == im.CCID)
    .DefaultIfEmpty()
from um in ctx.UnitsOfMeasures
    .Where(um => um.UOMID == sp.UOMID)
    .DefaultIfEmpty()

select new
{ my variables}

var querylist = sqlQuery.Where(n => n.SupplierID == thisSupplier).ToList();

我也试过

from s in ctx.Suppliers
    join sp in ctx.SupplierParts on s.SupplierID equals sp.SupplierID
    join sm in ctx.SupplierManufacturerRelations on sp.SupplierPNID equals sm.SupplierPNID into spartgroup
from sm in spartgroup.DefaultIfEmpty()
    join mp in ctx.ManufacturerParts on sm.MfgPNID equals mp.MfgPNID into mpartgroup
from mp in mpartgroup.DefaultIfEmpty()
     join m in ctx.Manufacturers on mp.ManufacturerID equals m.ManufacturerID into mgroup
from m in mgroup.DefaultIfEmpty()
     join im in ctx.ItemMasters 
     on new { key1 = (int)mp.PreID, key2 = (int)mp.PartNumber }
     equals new { key1 = im.PreID, key2 = im.PartNumber }
     into tpartgroup
from im in tpartgroup.DefaultIfEmpty()
     join c in ctx.ComponentClasses on im.CCID equals c.CCID into fullgroup
from c in fullgroup.DefaultIfEmpty()
     join um in ctx.UnitsOfMeasures on sp.UOMID equals um.UOMID

此SQL查询有效,并且不会省略行

    SELECT Supplier.SupplierID
         , SupplierPart.SupplierPNID
         , SupplierPart.SupplierPN
         , SupplierPart.Description
         , SupplierManufacturerRelation.MfgPNID
         , ManufacturerPart.PreID
         , ManufacturerPart.PartNumber
         , ItemMaster.CCID
         , ItemMaster.Description AS Expr1
      FROM Supplier  
Inner JOIN SupplierPart 
        ON Supplier.SupplierID = SupplierPart.SupplierID 
 Left JOIN SupplierManufacturerRelation 
        ON SupplierPart.SupplierPNID = SupplierManufacturerRelation.SupplierPNID 
 Left JOIN ManufacturerPart 
        ON SupplierManufacturerRelation.MfgPNID = ManufacturerPart.MfgPNID 
 Left JOIN ItemMaster 
        ON ManufacturerPart.PreID = ItemMaster.PreID 
       AND ManufacturerPart.PartNumber = ItemMaster.PartNumber
     WHERE Supplier.SupplierID = 9

1 个答案:

答案 0 :(得分:0)

将SQL转换为LINQ查询理解:

  1. 将FROM子选项转换为单独声明的变量。
  2. 以LINQ子句顺序翻译每个子句,将monadic运算符(DISTINCTTOP等)转换为应用于整个LINQ查询的函数。
  3. 使用表别名作为范围变量。使用列别名作为匿名类型字段名称。
  4. 对多列使用匿名类型(new { ... })。
  5. 通过使用into join_variable并从join变量后跟.DefaultIfEmpty()执行另一个来模拟左连接。
  6. 用条件运算符和空值测试替换COALESCE
  7. IN翻译为.Contains(),将NOT IN翻译为! ... Contains()
  8. SELECT *必须替换为select range_variable或者连接,一个包含所有范围变量的匿名对象。
  9. SELECT字段必须替换为select new { ... },以创建包含所有所需字段或表达式的匿名对象。
  10. 必须使用扩展方法处理正确的FULL OUTER JOIN
  11. 因此,从您的SQL中,您的查询应如下所示:

    var ans = from s in ctx.Suppliers
              join sp in ctx.SupplierParts on s.SupplierID equals sp.SupplierID
              join sm in ctx.SupplierManufacturerRelations on sp.SupplierPNID equals sm.SupplierPNID into smj
              from sm in smj.DefaultIfEmpty()
              join mp in ctx.ManufacturerParts on sm?.MfgPNID equals mp.MfgPNID into mpj
              from mp in mpj.DefaultIfEmpty()
              join im in ctx.ItemMasters on new { key1 = (int)mp.PreID, key2 = (int)mp.PartNumber } equals new { key1 = im.PreID, key2 = im.PartNumber } into imj
              from im in imj.DefaultIfEmpty()
              select new {
                  s.SupplierID, sp.SupplierPNID, sp.SupplierPN, sp.Description, sm.MfgPNID, mp.PreID, mp.PartNumber, im.CCID, Expr1 = im.Description
              };