2

ここSOや他の場所にLINQネストクエリの数え切れないほどの例があることは知っていますが、それは私には意味がありません。私が5歳のように誰かがこれを説明できれば、私はとても感謝しています。これはすべて疑似難読化されているため、この不自然な例に我慢してください。

私はこれらを持っているEFモデルを持っています:

public class Car(){
  public String Vin {get; private set;}
  public string Type {get; private set;}
  public List<Option> Options {get; set;}
}

public class Option(){
  public string Name { get; set; }
}

IQueryable<Car> carsリポジトリからコレクションを取得します。

十分に単純です。目標は次のとおりです。

  1. すべての車種を一覧表示します(「トラック」、「SUV」、「ミニバン」など)
  2. これらの各タイプの下に、そのタイプの車に存在するオプション名のサブリストがあります。
  3. 各オプションの下に、そのオプションがあり、そのタイプの各車のVINをリストします。

したがって、リストは次のようになります。

  • トラック
    • トレーラーヒッチ
      • vin1
      • vin8
    • トラックナッツ
      • vin2
      • vin3
      • vin4
    • ガンラック
      • vin1
    • 折りたたみ式リアシート
      • vin2
      • vin3
  • ミニバン
    • 回転シート
      • vin6
    • DVDプレーヤー
      • vin6
      • vin10
    • 折りたたみ式リアシート
      • vin6
      • vin10
  • SUV
    • 折りたたみ式リアシート
      • vin9
      • vin5

あなたはおそらくその考えを理解するでしょう。次のように、車をタイプ別にグループ化できることを知っています。

from c in cars
group by c.Type into g

しかし、私がする必要があるのは、グループVin化しOptionて、結果をタイプにグループ化することだと思います。私もする必要があるかもしれないと思います

cars.SelectMany(c => c.Options)
    .Select(o => o.Name)
    .Distinct();

一意のオプション名のリストを取得しますが、a)これがこれを行う最も効率的な方法であり、b)これをグループ化クエリに組み込む方法がわかりません。これを実現するためにネストされたグループ化クエリを作成する方法がよくわかりません。最初のグループは外部グループですか、それとも内部グループですか。

これについての私の理解は改善の余地がないので、もう一度お願いします。私が5歳のように説明してください。

ありがとうございます。

4

3 に答える 3

2

それは確かに些細な質問ではありません。

私はそれを次のようにします:

cars.SelectMany(c => c.Options.Select(o => new { Car = c, Option = o.Name }))
    .GroupBy(x => x.Car.Type)
    .Select(x => new
                 {
                     Type = x.Key,
                     Options = x.GroupBy(y => y.Option, y => y.Car.Vin)
                                .Select(y => new { Option = y.Key,
                                                   Cars = y.ToList() } )
                 });

このクエリは次のことを行います。

  1. 処理しやすいように、作業するデータを少し変更します。車の上にオプションが必要です。つまり、最終結果では、各車が複数のオプションの下にある可能性があるため、実際に必要なのは(Option、Car)タプルのリストです。

    これを達成するには

    cars.SelectMany(c => c.Options.Select(o => new { Car = c, Option = o.Name }))
    

    これは基本的に次のように述べています。各車と各オプションについて、プロパティとして車とオプション名を使用して新しい匿名タイプを選択します。その匿名タイプにAno1という名前を付けましょう。

    結果はになりますIEnumerable<Ano1>

  2. このフラットなデータは、車のタイプごとにグループ化されています。これは、車種ごとにAno1インスタンスのリストがあることを意味します。これで、グループのリストが作成され、各グループにはAno1インスタンスのリストがあります。

  3. このグループのリストで、selectを発行します。各グループ(=車のタイプ)について、selectは、車のタイプのプロパティ(情報が失われないようにするため)とオプションのプロパティを持つ新しい匿名タイプを返します。

  4. 前の手順のオプションは、最終的にはOptionプロパティとCarsプロパティを持つ匿名タイプのリストになります。このデータを取得するには、オプションですべてのAno1インスタンスをグループ化し、グループ内の要素として車のVINを選択します。これらのグループは、オプション名のプロパティと車のプロパティを持つ新しい匿名タイプに変換されます。

クエリは簡単ではなく、説明も簡単ではありません。不明な点がないかお尋ねください。

于 2012-09-20T16:01:02.567 に答える
2

このlinq-to-entitiesクエリはトリックを実行します

var query = from c in cars
            group c by c.Type into g
            select new {
              Type = g.Key,
              Options = from o in g.Options.SelectMany(x => x.Options).Distinct()
                        select new {
                          o.Name,
                          Vins = from c in cars
                                 where c.Options.Any(x => x.Name == o.Name)
                                 where c.Type == g.Key
                                 select c.Vin
                        }
            }
于 2012-09-20T16:03:06.950 に答える
2

これはきれいになることはなく、L2Eがこれを処理するかどうかわからない場合は、データベースからリスト全体を選択して、L2Oでこれを行う必要があります。

var result = cars.GroupBy(c => c.Type)
            .Select(c => new {
               Type = c.Key,
               Options = c.SelectMany(x => x.Options)
                           .GroupBy(x => x.Name)
                           .Select(x => new {
                                  Option = x.Key ,
                                  Vins = c.Where(y => y.Options.Any(z => z.Name == x.Key)).Select(z => z.Vin)
                           })
            });

実例(モデル化されたトラックだけですが、すべてで機能します): http: //rextester.com/OGD12123

于 2012-09-20T16:08:52.853 に答える