2

我知道在 SO 和其他地方有大量的LINQ嵌套查询示例,但这对我来说没有意义。如果有人能像我五岁一样解释这一点,我将不胜感激。这都是伪混淆,所以请耐心等待这个人为的例子。

我有一个具有这些的 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
      • 葡萄酒8
    • 卡车螺母
      • vin2
      • VIN3
      • vin4
    • 枪架
      • vin1
    • 折叠后座
      • vin2
      • VIN3
  • 小型货车
    • 旋转座椅
      • vin6
    • DVD播放机
      • vin6
      • VIN10
    • 折叠后座
      • vin6
      • VIN10
  • 越野车
    • 折叠后座
      • 葡萄酒9
      • vin5

你可能明白了。我知道我可以按类型对汽车进行分组,如下所示:

from c in cars
group by c.Type into g

但我认为我需要做的是将结果分组VinOption分组为 Type。我也觉得我可能需要

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

获取唯一选项名称的列表,但我不确定 a)这是执行此操作的最有效方法以及 b)如何将其合并到我的分组查询中。我真的不明白如何编写嵌套分组查询来完成此操作 - 第一组是外部组还是内部组?

我对此的理解低于补救措施,所以请再次:像我五岁一样解释。

谢谢大家。

4

3 回答 3

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 回答
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. 在这个组列表中,我们发出一个选择。对于每个组(= 汽车类型),选择返回一个新的匿名类型,其中包含汽车类型的属性 - 这样信息不会丢失 - 以及选项的属性。

  4. 上一步中的选项最终将是一个匿名类型列表,具有 Option 和 Cars 属性。为了获取这些数据,我们通过 Option 对我们的所有 Ano1 实例进行分组,并选择汽车的 VIN 作为组内的元素。这些组现在转换为一个新的匿名类型,其中一个属性用于选项名称,一个属性用于汽车。

查询不是微不足道的,解释也是如此。请询问是否有不清楚的地方。

于 2012-09-20T16:01:02.567 回答