1. ホーム
  2. c#

[解決済み] Linq - SelectManyの混乱

2023-05-31 22:48:43

質問

私がSelectManyのドキュメントから理解したところでは、1-many関係の(平坦化された)シーケンスを生成するためにそれを使用することができます。

私は以下のクラスを持っています。

  public class Customer
  {
    public int Id { get; set; }
    public string Name { get; set; }
  }

  class Order
  {
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public string Description { get; set; }
  }

次に、これらをクエリ式の構文を使って、次のように使ってみます。

  var customers = new Customer[]
  {
    new Customer() { Id=1, Name ="A"},
    new Customer() { Id=2, Name ="B"},
    new Customer() { Id=3, Name ="C"}
  };

  var orders = new Order[]
  {
    new Order { Id=1, CustomerId=1, Description="Order 1"},
    new Order { Id=2, CustomerId=1, Description="Order 2"},
    new Order { Id=3, CustomerId=1, Description="Order 3"},
    new Order { Id=4, CustomerId=1, Description="Order 4"},
    new Order { Id=5, CustomerId=2, Description="Order 5"},
    new Order { Id=6, CustomerId=2, Description="Order 6"},
    new Order { Id=7, CustomerId=3, Description="Order 7"},
    new Order { Id=8, CustomerId=3, Description="Order 8"},
    new Order { Id=9, CustomerId=3, Description="Order 9"}
  };

  var customerOrders = from c in customers
                       from o in orders
                       where o.CustomerId == c.Id
                       select new 
                              { 
                                 CustomerId = c.Id
                                 , OrderDescription = o.Description 
                              };

  foreach (var item in customerOrders)
    Console.WriteLine(item.CustomerId + ": " + item.OrderDescription);

これは私が必要とするものを与えてくれます。

1: Order 1
1: Order 2
1: Order 3
1: Order 4
2: Order 5
2: Order 6
3: Order 7
3: Order 8
3: Order 9

これは、クエリ式構文を使用していないときにSelectManyメソッドを使用することに変換されると思いますが?

いずれにせよ、私はSelectManyを使用することについて理解しようとしています。上記のクエリが SelectMany に変換されない場合でも、2 つのクラスとモック データがあれば、SelectMany を使用する linq クエリを誰かが提供してくれますか?

どのように解決するのですか?

以下は SelectMany を使用して、あなたの例とまったく同じようにモデル化されたクエリです。同じ出力です!

        var customerOrders2 = customers.SelectMany(
            c => orders.Where(o => o.CustomerId == c.Id),
            (c, o) => new { CustomerId = c.Id, OrderDescription = o.Description });

最初の引数は、各顧客を注文のコレクションにマップします(すでに持っている 'where' 節と完全に類似しています)。

第2引数は各一致ペア{(c1, o1), (c1, o2) ... (c3, o9)}を新しい型に変換しますが、これはあなたの例と同じように作りました。

というわけで。

  • arg1はベースコレクションの各要素を別のコレクションにマップします。
  • arg2 (オプション) は各ペアを新しい型に変換します。

結果として得られるコレクションは、元の例で期待したような平坦なものになります。

もし、2番目の引数を省略すると、顧客に一致するすべての注文のコレクションになります。これは、単に Order オブジェクトのフラット コレクションです。

使いこなすには慣れが必要で、今でも時々頭を悩ませています :(