我正在努力弄清楚特定查询的Linq-to-SQL语法是什么。我可以在SQL中轻松完成这项工作,但我无法在Linq中获得正确的语法。
我在两个数据库表中有父记录和子记录,由外键链接。我希望我的结果根据这些规则返回行:
我已经在.NET Fiddle中玩了一段时间,但我无法做到这一点。这是我到目前为止(忽略随机描述!):
IEnumerable<Parent> parents = new Parent[] {
new Parent { ID = 1, Description = "Apple" },
new Parent { ID = 2, Description = "Orange" },
new Parent { ID = 3, Description = "Pear" },
new Parent { ID = 4, Description = "Banana" } };
IEnumerable<Child> children = new Child[] {
new Child { ID = 1, ParentID = 2, Description = "Mercury", Condition = null },
new Child { ID = 2, ParentID = 3, Description = "Venus", Condition = null },
new Child { ID = 3, ParentID = 3, Description = "Earth", Condition = null },
new Child { ID = 4, ParentID = 4, Description = "Mars", Condition = null },
new Child { ID = 5, ParentID = 4, Description = "Saturn", Condition = "> 5" } };
/// What goes here...?
var query = from p in parents
join c in children on p.ID equals c.ParentID into jc
from subchildren in jc.DefaultIfEmpty()
select new Item {
ParentID = p.ID,
Description = p.Description,
PrimaryChildID = subchildren == null ? 0 : subchildren.ID,
SubDescription = subchildren == null ? null : subchildren.Description,
ConditionalCount = 0};
foreach (var item in query)
Console.WriteLine("{0} {1} {2} {3} {4}",
item.ParentID,
item.PrimaryChildID,
item.Description,
item.SubDescription,
item.ConditionalCount);
我得到的输出是:
1 0 Apple 0
2 1 Orange Mercury 0
3 2 Pear Venus 0
3 3 Pear Earth 0
4 4 Banana Mars 0
4 5 Banana Saturn 0
但我想要这个:
1 0 Apple 0
2 1 Orange Mercury 0
3 2 Pear Venus 0
4 4 Banana Mars 1
任何人都可以帮我解决此查询的正确语法吗?
答案 0 :(得分:2)
在您的情况下,您不需要left join
,而是需要group join
。
根据MSDN: -
The group join is useful for producing hierarchical data structures.
It pairs each element from the first collection with a set of correlated elements
from the second collection.
这样做: -
var query = from p in parents
join c in children
on p.ID equals c.ParentID into g
let firstNullElement = g.FirstOrDefault(x => x.Condition == null)
select new
{
ParentID = p.ID,
PrimaryChildID = firstNullElement != null ? firstNullElement.ID : 0,
Description = p.Description,
SubDescription = firstNullElement!= null ? firstNullElement.Description
: String.Empty,
ConditionalCount = g.Count(x => x.Condition != null)
};
为了正确解释,以下是在我们使用select new { }
投影实际所需数据之前生成的内容,(证明Group Join
的定义是合理的): -
ParentId g
----------------------------------------------
1 null
2 ID = 1, ParentID = 2, Description = "Mercury", Condition = null
3 ID = 2, ParentID = 3, Description = "Venus", Condition = null
ID = 3, ParentID = 3, Description = "Earth", Condition = null
4 ID = 4, ParentID = 4, Description = "Mars", Condition = null
ID = 5, ParentID = 4, Description = "Saturn", Condition = "> 5"
现在,由于g
持有IEnumerable
个子元素,我们可以应用过滤器,项目数据,计数或做任何我们想做的事情,就像我们在使用select
的最终语句中所做的那样。而且,正如我们所看到的,没有任何数据来自不同的子元素。
以下是完整的Working Fiddle。
答案 1 :(得分:0)
这应该做的事情
var query = (from p in parents
select new
{
ParentID = p.ID,
Description = p.Description,
PrimaryChildID = children.Where(c => c.ParentID == p.ID && c.Condition == null).Count() == 0 ? 0 : children.OrderBy(c=>c.ID).FirstOrDefault(c => c.ParentID == p.ID && c.Condition == null).ID,
SubDescription = children.Where(c => c.ParentID == p.ID && c.Condition == null).Count() == 0 ? null : children.OrderBy(c => c.ID).FirstOrDefault(c => c.ParentID == p.ID && c.Condition == null).Description,
ConditionalCount = children.Where(c => c.ParentID == p.ID && c.Condition != null).Count()
}).ToList();
答案 2 :(得分:0)
这是我的查询变体:
var query = from p in parents
join c in children on p.ID equals c.ParentID into jc
from subchildren in jc.DefaultIfEmpty()
select new
{
Parent = p,
Subchildren = subchildren
} into itemData
group itemData by itemData.Parent into g
select new Item
{
ParentID = g.Key.ID,
Description = g.Key.Description,
PrimaryChildID = g.Select(_ => _.Subchildren == null ? 0 : _.Subchildren.ID).FirstOrDefault(),
SubDescription = g.Select(_ => _.Subchildren == null ? null : _.Subchildren.Description).FirstOrDefault(),
ConditionalCount = 0
};