[英]Linq reducing one-to-many relationship to one-to-one
List<dynamic> a = new List<dynamic>();
a.Add(new { Foo = 1, Baz = "Inga", Name = "Alice"});
a.Add(new { Foo = 2, Baz = "Baz", Name = "Bob"});
a.Add(new { Foo = 3, Baz = "Hi", Name = "Charlie"});
List<dynamic> b = new List<dynamic>();
b.Add(new { Foo = 1, Value = "Bar", Code = "A"});
b.Add(new { Foo = 1, Value = "Quux", Code = "B"});
b.Add(new { Foo = 2, Value = "Bar", Code = "C"});
b.Add(new { Foo = 3, Value = "Mint", Code = "A"});
b.Add(new { Foo = 3, Value = "Seven", Code = "Q"});
b.Add(new { Foo = 3, Value = "Threeve", Code = "T"});
好的....所以我有一個問題( 自然地 ),這是人為設計和簡化的,以專注於手頭的問題。 我需要修改一個Linq查詢以將兩個列表投影到以下響應:
[
{ Foo = 1
, Baz = "Inga"
, Code = "A"
, Bars = [{ Value = "Bar", Code = "A"}
,{ Value = "Quux", Code = "B"}
]
}
,{ Foo = 2
, Baz = "Baz"
, Code = "C"
, Bars = [{ Value = "Fizz", Code = "C"}]
}
,{ Foo = 3
, Baz = "Hi"
, Code = "A"
, Bars = [{ Value = "Mint", Code = "A"}
,{ Value = "Seven", Code = "Q"}
,{ Value = "Threeve", Code = "T"}
]
}
]
有什么辦法可以查詢集合b進行選擇
(b.First Where Distinct By b.Foo) AsEnumerable()
?
我需要選擇的投影a
,但因為它是被物化,確定第一Code
列表b
其中b.Foo == a.Foo
並把b.Code
直接上a
。 然后需要將b中b.Foo == a.Foo
的項目放入a.Bars
。
我手上的問題是我無法識別單數a
因此無法預先選擇a
和b
值來簡化這種混亂情況,並且沒有機會進行建模。
因此,如果我要搜索Where Value = Bar
; 愛麗絲和鮑勃需要返回正確的映射和投影。
天真的嘗試是...
var results = a.Join( b
, master => master.Foo
, detail => detail.Foo
, (master, detail) => new { master, detail})
.Select(item => new
{
item.master.Foo
, item.master.Baz
, item.master.Name
, item.detail.Code
, Bars = b.Select(x => x.Foo.Equals(item.master.Foo))
};
但這導致我的結果包含重復的“ Alice”記錄和重復的“ Charlie”記錄,因為它內部連接了a和b。 我真正想做的(偽)是
a.Join(
b.Where(b.Foo.Equals(a.Foo)).First()
, master => master.Foo
, detail => detail.Foo
, (master, detail) => new { master, detail}
)
.Select(item => new
{
item.master.Foo
, item.master.Baz
, item.master.Name
, item.detail.Code
, Bars = b.Select(x => x.Foo.Equals(item.master.Foo))
};
但是無論我怎么嘗試,都會變得一團糟。
...注意,由於投影是匿名的,因此我不能采取幼稚的方法然后運行
DistinctBy
。
誰能完全使用Linq to Object查詢解決此問題? (注意:我不需要單次通過分辨率)
如果我理解正確的話,該Code
在一個單一的結果條目只是Code
的第一次加入的b
元素。
所以試試這個:
var result = a.GroupJoin(b,
a0 => a0.Foo,
b0 => b0.Foo,
(a0, bs) =>
new
{
Foo = a0.Foo,
Baz = a0.Baz,
Code = bs.Select(b1 => b1.Code).FirstOrDefault(),
Bars = bs.Select(b1 => new {b1.Value, b1.Code}).ToArray()
}).ToArray();
GroupJoin是您在這里需要的。 你能想到的Join
類似SelectMany
而GroupJoin
-樣Select
。 所不同的是所述突起的所述第二參數的類型- TInner
用於Join
和IEnumerable<TInner>
為GroupJoin
。 在LINQ語法中, GroupJoin
通過into
子句實現。
話雖如此,這是兩種語法在示例中的查找方式:
var resultsA = a.GroupJoin(b, master => master.Foo, detail => detail.Foo, (master, details) => new
{
master.Foo,
master.Baz,
master.Name,
Code = details.Select(detail => detail.Code).First(),
Bars = details.Select(detail => new { detail.Value, detail.Code })
});
var resultsB =
from master in a
join detail in b on master.Foo equals detail.Foo into details
select new
{
master.Foo,
master.Baz,
master.Name,
Code = details.Select(detail => detail.Code).First(),
Bars = details.Select(detail => new { detail.Value, detail.Code })
};
var query = from ai in a
let bs = b.Where(bi => bi.Foo == ai.Foo)
select new
{
ai.Foo,
ai.Baz,
Code = bs.Select(bi => bi.Code).FirstOrDefault(),
Bars = bs.Select(bi => new { bi.Value, bi.Code }),
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.