如何在Linq中使用coalesce执行左连接?
以桌子为例如何在Linq中使用coalesce执行左连接?,linq,left-join,coalesce,Linq,Left Join,Coalesce,以桌子为例 发明,发明清单 组件,可用于发明的所有组件列表,以及 发明组件,发明中使用组件的列表,带计数 对于给定的发明&发明ID,我希望对所有组件进行“覆盖”左连接,而不仅仅是使用的组件 SQL将类似于 select I.name as inventionName , C.name as componentName , coalese (IC.count, 0) as componentCount from (select &inventionID as inventio
- 发明,发明清单
- 组件,可用于发明的所有组件列表,以及
- 发明组件,发明中使用组件的列表,带计数
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
NET FIDLE at中的示例数据和Linq查询导致异常
[System.NullReferenceException: Object reference not set to an instance of an object.]
问题:应该如何修改Linq查询以执行所需的覆盖查询
为了完整起见,这里重复了C#fiddle代码
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; }
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
公共课程
{
公共静态void Main()
{
var组件=新列表{
新组件{ID=1,Name=“Florgebit”},
新组件{ID=2,Name=“Phadron”},
新组件{ID=3,Name=“Goobstem”},
新组件{ID=4,Name=“Larchwren”},
新组件{ID=5,Name=“zangpound”},
新组件{ID=6,Name=“Spoofork”},
新组件{ID=7,Name=“Forkoon”},
新组件{ID=8,Name=“Blidget”},
新组件{ID=9,Name=“Wazzawim”},
新组件{ID=10,Name=“Klackberg”},
};
var=新列表{
新发明{ID=21,Name=“swazzute”},
新发明{ID=22,Name=“Corpocran”},
新发明{ID=23,Name=“Fillyboof”},
};
var inventionComponents=新列表{
新发明组件{ID=100,发明ID=21,组件ID=1,计数=1},
新发明组件{ID=101,发明ID=21,组件ID=2,计数=2},
新发明组件{ID=102,发明ID=21,组件ID=8,计数=3},
新发明组件{ID=103,发明ID=23,组件ID=5,计数=4},
新发明组件{ID=104,发明ID=23,组件ID=6,计数=5},
新发明组件{ID=105,发明ID=23,组件ID=3,计数=4},
新发明组件{ID=106,发明ID=21,组件ID=4,计数=3},
新发明组件{ID=107,发明ID=22,组件ID=5,计数=2},
新发明组件{ID=108,发明ID=22,组件ID=4,计数=1},
新发明组件{ID=109,发明ID=22,组件ID=1,计数=6},
新发明组件{ID=110,发明ID=22,组件ID=7,计数=1},
新发明组件{ID=111,发明ID=21,组件ID=9,计数=1},
};
var详细信息=
从发明的角度来看
将B加入A.ID上的发明组件等于B.InnovationID
将C连接到B上的组件中。ComponentID等于C.ID
按A.名称、C.名称排序
选择新的{
发明名称=A.名称,
ComponentName=C.名称,
组件计数=B.计数
};
/*
foreach(详细信息为var d)
{
WriteLine(“发明:{0},组件:{1},计数:{2}”,d.InventionName,d.ComponentName,d.ComponentCount);
}
*/
var=22;
var指数=1;
//想要全面覆盖发明ID、组件ID和应用计数
// 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=
从components中的C选择新的{InventionID=InventionID,ComponentID=C.ID,ComponentName=C.Name}进入allcomps
将新{allcomps.InventionID,allcomps.ComponentID}上的发明组件中的B连接到join1中
//从接头1/内部接头中的j1开始
从join1.DefaultIfEmpty()中的j1开始//导致异常
orderby allcomps.ComponentName
选择新的{
RowNum=index++,
发明ID=所有公司发明ID,
ComponentName=allcomps.ComponentName,
组件计数=j1.计数,
};
foreach(corpcheck中的变量x)
{
WriteLine(“发明ID:{0},RowNum:{1},组件名称:{2},计数:{3}”,x.InventionID,x.RowNum,x.ComponentName,x.ComponentCount);
}
}
公共类发明
{
公共int ID{get;set;}
公共字符串名称{get;set;}
}
公共类发明组件
{
公共int ID{get;set;}
public int InventionID{get;set;}
公共int组件ID{get;set;}
公共整数计数{get;set;}
}
公共类组件
{
公共int ID{get;set;}
公共字符串名称{get;set;}
}
}
通过添加DefaultIfEmpty()
,j1
对于某些组件可以为空。如果j1
为空,我假设您希望计数为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对象中,您还可以使用ComponentCount=j1?.Count??0
。但我假设您将在LINQ中使用它作为SQL后端