簡體   English   中英

Linq將一對多關系減少為一對一

[英]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"}
              ]
    }
]

首先,TL; DR

有什么辦法可以查詢集合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因此無法預先選擇ab值來簡化這種混亂情況,並且沒有機會進行建模。

因此,如果我要搜索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查詢解決此問題? (注意:我不需要單次通過分辨率)

我只是堅持將第二組分組(在此表示為b ),然后將其與查找結果配對使用以構成投影。

var results = b.GroupBy( d => d.Foo ).Select( g => new {
    Foo = g.Key,
    Baz = a.First( i => i.Foo == g.Key ).Baz,
    Code = g.First().Code,
    Bars = g.Select( e => new { Value = e.Value, Code = e.Code }).ToArray()
});

在此處輸入圖片說明

如果我理解正確的話,該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類似SelectManyGroupJoin -樣Select 所不同的是所述突起的所述第二參數的類型- TInner用於JoinIEnumerable<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM