在LINQ中同时区分和分组?

时间:2011-01-22 09:06:19

标签: entity-framework c#-4.0 linq-to-entities group-by distinct

假设我有以下课程:

Product { ID, Name }

Meta { ID, Object, Key, Value }

Category { ID, Name }

Relation {ID, ChildID, ParentID } (Child = Product, Parent = Category)

以及一些示例数据:

产品:

ID   Name

1    Chair
2    Table

ID   Object  Key     Value

1      1     Color   "Red"
2      1     Size    "Large"
3      2     Color   "Blue"
4      2     Size    "Small"

分类

ID   Name

1    Indoor
2    Outdoor

关系

ID   ChildID   ParentID

1       1         1
2       1         2
3       2         1

我们可以使用Distinct和Group by来生成以下格式(ProductDetail)

ID=1,
Name=Chair,
Parent=
{
  { ID=1, Name="Indoor" },
  { ID=2, Name="Outdoor" }
},
Properties { Color="Red", Size="Large" }

ID=2,
Name=Table,
Parent=
{
  { ID=1, Name="Indoor"}
},
Properties { Color = "Blue", Size = "Small" }

我们可以使用

获取第一个项目的“颜色”值
ProductDetails[0].Properties.Color

任何帮助都将不胜感激!

2 个答案:

答案 0 :(得分:0)

不,你不能根据你所说的做到这一点 - 因为“颜色”和“大小”是数据的一部分,而不是模型的一部分< / em>的。它们只在执行时才知道,因此除非您使用动态类型,否则您无法通过Properties.Color访问它。

但是,您可以使用Properties["Color"]

var query = from product in db.Products
            join meta in db.Meta 
                on product.ID equals meta.Object 
                into properties
            select new { Product = product,
                         Properties = properties.ToDictionary(m => m.Key,
                                                              m => m.Value) };

因此,对于每种产品,您都会拥有一本属性字典。这可以逻辑,但您可能需要调整它以使其在实体框架中工作 - 我不知道它是如何支持ToDictionary的。

编辑:好的,我将上述内容保留为“理想”解决方案,但如果EF不支持ToDictionary,则必须在进程中执行该部分:

var query = (from product in db.Products
             join meta in db.Meta 
                 on product.ID equals meta.Object 
                 into properties
             select new { product, properties })
            .AsEnumerable()
            .Select(p => new {
                    Product = p.product,
                    Properties = p.properties.ToDictionary(m => m.Key,
                                                           m => m.Value) });

答案 1 :(得分:0)

我在学习LINQ的过程中遇到过这个问题,但我对Jon的输出与问题相符并不满意(对不起Jon)。以下代码返回一个匿名类型对象的List,它更符合您的问题结构:

var ProductDetails = (from p in Product
                      let Parents = from r in Relation
                                    where r.ChildID == p.ID
                                    join c in Category on r.ParentID equals c.ID
                                        into RelationCategory
                                    from rc in RelationCategory
                                    select new
                                    {
                                        rc.ID,
                                        rc.Name
                                    }
                      join m in Meta on p.ID equals m.Object into ProductMeta

                      select new
                      {
                          p.ID,
                          p.Name,
                          Parent = Parents.ToList(),
                          ProductMeta
                      })
                     .AsEnumerable()
                     .Select(p => new
                     {
                         p.ID,
                         p.Name,
                         p.Parent,
                         Properties = p.ProductMeta
                                       .ToDictionary(e => e.Key, e => e.Value)
                     }).ToList();

主要归功于Jon Skeet和Visual Studio调试器;)

我意识到你现在可能已经开始了,但希望这可能会帮助其他想要学习LINQ的人,就像我一样。