考虑表
对于给定的发明,& InventionID,我想对所有组件进行“覆盖”左连接,而不仅仅是使用的组件。
SQL就像
select
I.name as inventionName
, C.name as componentName
, coalese (IC.count, 0) as componentCount
from
(select &inventionID as inventionID, ID, name from components) C -- all components applied to some &inventionID
left join
inventionComponents IC
on
C.ID = IC.ComponentID
and C.inventionID = IC.inventionID
join
inventions I
on
I.ID = C.inventionID
https://dotnetfiddle.net/cx4bHp中.NET示例中的示例数据和Linq查询导致异常
[System.NullReferenceException: Object reference not set to an instance of an object.]
问题:如何修改Linq查询以执行所需的覆盖查询?
为完整起见,此处重复C#小提琴代码
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var components = new List<Component>{
new Component { ID=1, Name = "Florgebit" },
new Component { ID=2, Name = "Phadron" },
new Component { ID=3, Name = "Goobstem" },
new Component { ID=4, Name = "Larchwren" },
new Component { ID=5, Name = "Zangponder" },
new Component { ID=6, Name = "Spoofork" },
new Component { ID=7, Name = "Forkoon" },
new Component { ID=8, Name = "Blidget" },
new Component { ID=9, Name = "Wazzawim" },
new Component { ID=10, Name = "Klackberg" },
};
var inventions = new List<Invention>{
new Invention { ID=21, Name = "Swazzlute" },
new Invention { ID=22, Name = "Corpocran" },
new Invention { ID=23, Name = "Fillyboof" },
};
var inventionComponents = new List<InventionComponent>{
new InventionComponent { ID=100, InventionID=21, ComponentID=1, Count=1 },
new InventionComponent { ID=101, InventionID=21, ComponentID=2, Count=2 },
new InventionComponent { ID=102, InventionID=21, ComponentID=8, Count=3 },
new InventionComponent { ID=103, InventionID=23, ComponentID=5, Count=4 },
new InventionComponent { ID=104, InventionID=23, ComponentID=6, Count=5 },
new InventionComponent { ID=105, InventionID=23, ComponentID=3, Count=4 },
new InventionComponent { ID=106, InventionID=21, ComponentID=4, Count=3 },
new InventionComponent { ID=107, InventionID=22, ComponentID=5, Count=2 },
new InventionComponent { ID=108, InventionID=22, ComponentID=4, Count=1 },
new InventionComponent { ID=109, InventionID=22, ComponentID=1, Count=6 },
new InventionComponent { ID=110, InventionID=22, ComponentID=7, Count=1 },
new InventionComponent { ID=111, InventionID=21, ComponentID=9, Count=1 },
};
var details =
from A in inventions
join B in inventionComponents on A.ID equals B.InventionID
join C in components on B.ComponentID equals C.ID
orderby A.Name, C.Name
select new {
InventionName = A.Name,
ComponentName = C.Name,
ComponentCount = B.Count
};
/*
foreach(var d in details)
{
Console.WriteLine("Invention: {0}, Component: {1}, Count: {2}", d.InventionName, d.ComponentName, d.ComponentCount);
}
*/
var inventionID = 22;
var index = 1;
// want full coverage of inventionID, componentID with applied counts
// 22,1,6
// 22,2,**0**
// 22,3,**0**
// 22,4,1
// 22,5,2
// 22,6,**0**
// 22,7,1
// 22,8,**0**
// 22,9,**0**
// 22,10,**0**
var corpcheck =
from C in components select new { InventionID = inventionID, ComponentID = C.ID, ComponentName = C.Name } into allcomps
join B in inventionComponents on new { allcomps.InventionID, allcomps.ComponentID } equals new { B.InventionID, B.ComponentID } into join1
// from j1 in Join1 // inner join
from j1 in join1.DefaultIfEmpty() // causes exception
orderby allcomps.ComponentName
select new {
RowNum = index++,
InventionID = allcomps.InventionID,
ComponentName = allcomps.ComponentName,
ComponentCount = j1.Count,
};
foreach(var x in corpcheck)
{
Console.WriteLine("InventionID: {0}, RowNum: {1}, ComponentName: {2}, Count: {3}", x.InventionID, x.RowNum, x.ComponentName, x.ComponentCount);
}
}
public class Invention
{
public int ID { get; set; }
public string Name { get; set; }
}
public class InventionComponent
{
public int ID { get; set; }
public int InventionID { get; set; }
public int ComponentID { get; set; }
public int Count { get; set; }
}
public class Component
{
public int ID { get; set; }
public string Name { get; set; }
}
}
答案 0 :(得分:2)
通过添加DefaultIfEmpty()
,j1
对于某些组件可以为null。如果j1
为空,我假设您希望count为0:
from C in components select new { InventionID = inventionID, ComponentID = C.ID, ComponentName = C.Name } into allcomps
join B in inventionComponents on new { allcomps.InventionID, allcomps.ComponentID } equals new { B.InventionID, B.ComponentID } into join1
from j1 in join1.DefaultIfEmpty()
orderby allcomps.ComponentName
select new {
RowNum = index++,
InventionID = allcomps.InventionID,
ComponentName = allcomps.ComponentName,
ComponentCount = j1 == null ? 0 : j1.Count, // add null check
};
在LINQ-to-objects中,您也可以使用ComponentCount = j1?.Count ?? 0
。但我假设您将在LINQ中将其用于SQL后端。