LINQ(lambda语法)选择多对多关系

时间:2014-03-17 14:48:07

标签: linq select lambda many-to-many

我有关系的实体:

包装M --- N工厂
包装M --- N组件

f.e。表的内容是:包装(Type1)有工厂(A,B,C)和组件(1,2,3,4)

我想写LINQ,它会给我结果:

Type1 A 1
Type1 A 2
Type1 A 3
Type1 A 4
Type1 B 1
Type1 B 2
Type1 B 3
Type1 B 4
Type1 C 1
Type1 C 2
Type1 C 3
Type1 C 4

如何使用LINQ和lambda语法来实现这一点?

2 个答案:

答案 0 :(得分:1)

您正在寻找的是笛卡尔积。我将定义两个小对象,以便我可以显示具体的LINQ查询。为方便起见,我将使包类型为enum,但实际上只要表示工厂和组件的对象具有相同类型的公共字段就无关紧要。

private enum PackagingType
{
    Type1
};

private class Factory
{
    public string Name { get; set; }
    public PackagingType Type { get; set; }
}

private class Component
{
    public string Name { get; set; }
    public PackagingType Type { get; set; }
}

var factories = new List<Factory>
                    {
                        new Factory {Name = "A", Type = PackagingType.Type1},
                        new Factory {Name = "B", Type = PackagingType.Type1},
                        new Factory {Name = "C", Type = PackagingType.Type1}
                    };

var components = new List<Component>
                        {
                            new Component {Name = "1", Type = PackagingType.Type1},
                            new Component {Name = "2", Type = PackagingType.Type1},
                            new Component {Name = "3", Type = PackagingType.Type1},
                            new Component {Name = "4", Type = PackagingType.Type1}
                        };

然后我们可以使用LINQ扩展方法factoriescomponents字段上加入TypeJoin,后者会为我们返回笛卡尔积。看起来像是:

var cartesianProduct = factories.Join(components,
                                      factory => factory.Type,
                                      component => component.Type,
                                      (factory, component) =>
                                          new
                                          {
                                              Type = factory.Type,
                                              FactoryName = factory.Name,
                                              ComponentName = component.Name
                                          });

这导致输出:

Type1 A 1 
Type1 A 2 
Type1 A 3
Type1 A 4
Type1 B 1 
Type1 B 2
Type1 B 3
Type1 B 4
Type1 C 1 
Type1 C 2
Type1 C 3
Type1 C 4

如果你有一个基于Packaging的第三个具有多对多关系的对象,那么你可以简单地将该对象列表与其Type字段上的当前笛卡尔积一起加入,以获得跨所有三个对象的笛卡尔积。有关详细信息,请参阅Eric Lippert的回答here

答案 1 :(得分:1)

您想要从每个源项目中选择许多对象。 因此请使用SelectMany运算符

packagingCollection.SelectMany(p => p.Components.Select(c => new {
            P = p,
            C = c
        })).SelectMany(x => x.P.Factories.Select(f => new {
            P = x.P,
            C = x.C,
            F = f
        })).Select(y => new {
            PackagingName = y.P.Name,
            ComponentName = y.C.Name,
            FactoryName = y.F.Name
        })