我发现自己在LINQ中使用了这种模式:
class Thing
{
public int ID { get; set; }
public int ColorID { get; set; }
}
class Color
{
public int ID { get; set; }
public string Description { get; set; }
}
static void Main()
{
var things = new List<Thing> { new Thing { ID = 1, ColorID = 1 }, new Thing { ID = 2, ColorID = 1 }, new Thing { ID = 3, ColorID = 2 }, new Thing { ID = 4, ColorID = 1 } };
var colors = new List<Color> { new Color { ID = 1, Description = "red" }, new Color { ID = 2, Description = "green" }, new Color { ID = 3, Description = "blue" } };
var joined = (from thing in things
from color in colors
where thing.ColorID == color.ID
select new { ID = thing.ID, Color = color.Description }).ToArray();
foreach (var thing in joined)
{
Console.WriteLine("(" + thing.ID + ", " + thing.Color + ")");
}
//Writes:
//(1, red)
//(2, red)
//(3, green
//(4, red)
}
它的核心,四行查询语法,感觉非常像我可能在tSQL中编写的INNER JOIN
,但当我查看examples of LINQ query syntax for joins时,他们使用join
这个词,而上面的LINQ没有。
上面的LINQ正在执行的'join'是什么?如何在LINQ方法语法中重写它?
答案 0 :(得分:3)
就LINQ理解而言,它根本没有执行连接。它只是基于两个属性进行过滤,其中一个发生来自一个范围变量而另一个发生来自另一个。在方法语法中,您将其写为:
var joined = things.SelectMany(thing => colors,
(thing, color) => new { thing, color })
.Where(pair => pair.thing.ColorID == pair.color.ID)
.Select(pair => new { ID = pair.thing.ID,
Color = pair.color.Description })
.ToArray();
此处pair
由编译器有效地自动引入为透明标识符。这不是由于where
中的过滤,而是由于有多个from
子句...在第一个使用from
之后的每个SelectMany
子句,并引入了一个透明的标识符,允许您引用多个范围变量(thing
和color
),这些变量组成一个单独的对象,这样管道的每个阶段只能理论上处理一个值。
请注意,当您有两个from
条款时:
from person in people
from book in books
...... 行为就像笛卡尔联接......但LINQ允许更精细的东西,例如:
from person in people
from book in person.Books
换句话说,第二个序列可以取决于&#34;当前&#34;来自第一个序列的值。管道的任何后续阶段(例如,where
或select
)作用于每对:第一个序列中的一个,然后是第一个序列中的元素生成的第二个序列中的一个。