交叉表查询 (LINQ to DataSet)
除了查询单个表外,也可以在 LINQ to DataSet 中执行交叉表查询。这可以通过使用联接来完成。 联接就是将一个数据源中的对象与另一个数据源中具有相同公共属性的对象(例如产品或联系人 ID)相关联。 在面向对象的编程中,由于每个对象都有引用另一个对象的成员,所以对象间的关系相对较容易导航。但在外部数据库表中,导航关系不像这样简单。 数据库表不包含内置关系。在这些情况下,可以通过联接操作来匹配每个源中的元素。 例如,假设有两个分别包含产品信息和销售信息的表,您可以使用联接操作来匹配同一销售订单的销售信息和产品。
语言集成查询 (LINQ) 框架提供两个联接运算符:Join 和 GroupJoin。这些运算符执行同等联接:即仅在键相等时匹配两个数据源的联接。 (相对而言,Transact-SQL 支持 equals 以外的其他连接运算符,如 less than 运算符)。
对于关系数据库,Join 实现内部联接。 内部联接是仅返回在相对数据集中具有匹配对象的那些对象的一种联接类型。
对于关系数据库,GroupJoin 运算符没有直接等效项,它们实现内部联接和左外部联接的超集。左外部联接是一种即使在第二个集合中没有关联元素的情况下也会返回第一个(左侧)集合中每个元素的联接。
有关联接的更多信息,请参见联接运算。
示例
下面的示例对 AdventureWorks 示例数据库中的 SalesOrderHeader 和 SalesOrderDetail 表执行传统联接以获取 8 月份以来的在线订单。
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim orders As DataTable = ds.Tables("SalesOrderHeader")
Dim details As DataTable = ds.Tables("SalesOrderDetail")
Dim query = _
From order In orders.AsEnumerable() _
Join detail In details.AsEnumerable() _
On order.Field(Of Integer)("SalesOrderID") Equals _
detail.Field(Of Integer)("SalesOrderID") _
Where order.Field(Of Boolean)("OnlineOrderFlag") = True And _
order.Field(Of DateTime)("OrderDate").Month = 8 _
Select New With _
{ _
.SalesOrderID = order.Field(Of Integer)("SalesOrderID"), _
.SalesOrderDetailID = detail.Field(Of Integer)("SalesOrderDetailID"), _
.OrderDate = order.Field(Of DateTime)("OrderDate"), _
.ProductID = detail.Field(Of Integer)("ProductID") _
}
For Each order In query
Console.WriteLine(order.SalesOrderID & vbTab & _
order.SalesOrderDetailID & vbTab & _
order.OrderDate & vbTab & _
order.ProductID)
Next
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable orders = ds.Tables["SalesOrderHeader"];
DataTable details = ds.Tables["SalesOrderDetail"];
var query =
from order in orders.AsEnumerable()
join detail in details.AsEnumerable()
on order.Field<int>("SalesOrderID") equals
detail.Field<int>("SalesOrderID")
where order.Field<bool>("OnlineOrderFlag") == true
&& order.Field<DateTime>("OrderDate").Month == 8
select new
{
SalesOrderID =
order.Field<int>("SalesOrderID"),
SalesOrderDetailID =
detail.Field<int>("SalesOrderDetailID"),
OrderDate =
order.Field<DateTime>("OrderDate"),
ProductID =
detail.Field<int>("ProductID")
};
foreach (var order in query)
{
Console.WriteLine("{0}\t{1}\t{2:d}\t{3}",
order.SalesOrderID,
order.SalesOrderDetailID,
order.OrderDate,
order.ProductID);
}