【发布时间】:2018-02-21 00:53:19
【问题描述】:
我正在尝试使用 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
【问题讨论】:
-
首先,如果您想要“翻译”SQL 连接,您必须使用 LINQ
join语句,而不是where。但是您应该完全避免使用 LINQjoin。使用导航属性,即 LINQ 类模型中的关联。 -
您使用的是 LINQ-to-SQL 还是 EntityFramework 或其他一些 ORM?
-
我很确定我正在使用 LINQ-to-SQL 我正在使用 EntityFramwork 进行正常的数据库交互,但这是为了避免必须拉出所有表并将它们组合到程序中是我最初做的。
-
所以您使用的是 EntityFramework 而不是 LINQ-to-SQL,LINQ-to-SQL 本身就是一个 ORM,我非常怀疑您是否同时使用 2 个 ORM - 所以既然您是使用 ORM,按照@GertArnold 告诉的那样做,而不是尝试自己加入表 - 使用 EntityFramework 提供的
Navigation Properties,所以你的第一个“加入”应该简单地写成var supplierParts = ctx.Suppliers.SelectMany(x => x.SupplierParts)会给你一个 SupplierParts 的列表在所有供应商中 - 或者如果您只有一个供应商,那就是ctx.Suppliers.First().SupplierParts -
您是否考虑过将您的 SQL 查询作为用户存储过程保存在数据库中,然后从您的 .net 代码中调用用户存储过程?这也可以让您调整您的 sql 代码,而无需在以后重新编译您的代码。
标签: c# sql-server entity-framework linq