1

I have entities with relationships :

Packaging M---N Factories
Packaging M---N Components

f.e. content of tables is : Packaging (Type1) has factories (A, B, C) and Components (1, 2, 3, 4)

I want to write LINQ which will give me result as :

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

How can I get this using LINQ with lambda syntax ?

Peter R.
  • 85
  • 1
  • 4
  • 15

2 Answers2

1

What you're looking for is a Cartesian Product. I'm going to define two small objects so that I can show a concrete LINQ query. For convenience I'll make the package type an enum, but in reality it doesn't matter so long as the objects representing a factory and component have a common field of the same type.

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}
                        };

Then we can join factories to components on the Type field using the LINQ extension method Join, which returns a Cartesian Product for us. That looks like:

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

This results in the output:

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

If you had a third object with a Many to Many relationship based on Packaging then you could simply join that list of objects with the current Cartesian Product on its Type field to get a Cartesian Product across all three objects. See Eric Lippert's answer here for more information.

Community
  • 1
  • 1
Zack Butcher
  • 1,046
  • 7
  • 12
1

You want to select many objects from each source item. So use the SelectMany operator.

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
        })
nlips
  • 1,258
  • 9
  • 25
  • how can i modify this select to outer join ? because when Packagings do not have any components or factories, I wont get this Packagings. And I want to return all packagings, also with or without components or factories – Peter R. Mar 27 '14 at 07:35