使用LINQ访问数据集
王然
微软认证讲师
wangran@itgoldenbridge.com
点击添加MSN机器人小新
为您收听下载MSDN中文网络广播课程加油助力!
本次课程内容包括
? LINQ to DataSet 概述
- 数据集
- LINQ to DataSet
? LINQ to DataSet 查询
- 启用 LINQ to DataSet 功能 - 使用标准查询操作符 - 基于方法的查询 - 查询交叉表
- 查询类型化数据集
议程
? LINQ to DataSet 概述
- 数据集
- LINQ to DataSet
? LINQ to DataSet 查询
- 启用 LINQ to DataSet 功能 - 使用标准查询操作符 - 基于方法的查询 - 查询交叉表
- 查询类型化数据集
数据集(DataSet)
? DataSet 是更为广泛使用的 ADO.NET 组件
之一,它可以显式缓存不同数据源中的数 据。
? 在表示层上 , DataSet 与 GUI 控件紧密集
成,以进行数据绑定。
? 在中间层上,它提供保留数据关系形状的 缓存并包括快速简单查询和层次结构导航 服务,从而可以减少对数据库的请求数。
查询数据集
? DataSet 虽然具有突出的优点,但其查询功
能也存在限制。
? Select 方法可用于筛选和排序,
GetChildRows 和 GetParentRow 方法可用 于层次结构导航。
? 但对于更复杂的情况,开发人员必须编写
自定义查询。 这会使应用程序性能低下并 且难以维护。
使用LINQ to DataSet
? 使用 LINQ toDataSet 可以更快更容易地查询在
DataSet 对象中缓存的数据。
? 这些查询用编程语言本身表示,而不表示为嵌入
在应用程序代码中的字符串。
? LINQ to DataSet 可使 Visual Studio 开发人员的
工作效率更高,因为Visual Studio IDE 提供编译 时语法检查、静态类型化和对 LINQ 的智能感知 的支持。
? LINQ to DataSet 也可用于查询从一个或多个数据
源合并的数据。 这可以使许多需要灵活表示和处 理数据的方案能够实现。
使用原有ADO.NET代码
? 现有的 ADO.NET 2.0 代
码将继续在 LINQto
DataSet 应用程序中有效。 ? 右图阐释了 LINQ to
DataSet 与 ADO.NET2.0 和数据存储区的关系。
查询数据集
? 填充 DataSet
- XxxDataAdapter -LINQ to SQL
? 主要使用下面两个扩展类
-DataRowExtensions
-DataTableExtensions
? 查询支持
- 类型化数据集 - 非类型化数据集
构建N层应用程序
? 在 N 层应用程序中,DataSet 通常用于中
间层以缓存 Web 应用程序的信息。 ? LINQ to DataSet 查询功能通过扩展方法实
现 ,并扩展现有的 ADO.NET 2.0 DataSet。
议程
? LINQ to DataSet 概述
- 数据集
- LINQ to DataSet
? LINQ to DataSet 查询
- 启用 LINQ to DataSet 功能 - 使用标准查询操作符 - 基于方法的查询 - 查询交叉表
- 查询类型化数据集
启用 LINQ to DataSet 功能
? 要求 .NET Framework 3.5
? 引用 System.Data.DataSetExtensions 程
序集
使用标准查询运算符
? 可以使用下面LINQ标准查询运算符
- from
- where
select
基于方法的查询语法
? 表述 LINQ to DataSet 查询的另一种方法 ? 是对 LINQ 运算符方法的一系列直接方法调
用
? 需要将 Lambda 表达式作为参数进行传递
延迟查询
? 当查询旨在返回一系列值时,查询变量本
身只存储查询命令。
? 如果查询不包含可使查询立即执行的方法,
则查询的实际执行将会推迟 ,直到在 foreach 或 For Each 循环中循环访问查询 变量。
? 延迟执行可使多个查询组合在一起或使查
询得到扩展。
主动查询
? 使用下列方法可以进行主动查询:
-ToList<TSource>
-ToArray<TSource>
ToLookup
- ToDictionary
交叉表查询
? LINQ 提供两个联接运算符
- Join:对于关系数据库,Join 实现内部联接。 - GroupJoin:对于关系数据库,GroupJoin运算
符没有直接等效项 ,它们实现内部联接和左外 部联接的超集。
? 这些运算符执行同等联接,即仅在键相等
时匹配两个数据源的联接。
查询类型化数据集
? 对于类型化 DataSet,不必使用泛型Field
方法或SetField 方法即可访问列数据。 ? 由于 DataSet 中包括类型信息,因此属性
名称在编译时可用。
? LINQ to DataSet 提供对正确类型的列值的
访问,以便可以在编译代码时而不是在运 行时捕获类型不匹配错误。
比较 DataRow
? LINQ 定义多种用于比较源元素的集合运算
符以查看它们是否相等:
- Distinct:返回序列中的非重复元素
Union : 生成两个序列的并集 - Intersect:生成两个序列的交集- Except:生成两个序列的差集
? 这些运算符通过对每个元素集合调用
GetHashCode 和 Equals 方法来比较源元 素。
通过查询创建数据表
? CopyToDataTable 方法
? 它使用下面的过程通过查询创建DataTable
- CopyToDataTable 方法克隆源表中的 DataTable - 克隆的DataTable 的架构从源表中枚举的第一个
DataRow 对象的列生成,克隆表的名称是源表的名称 后面追加单词“query”。
- 对于源表中的每一行,会将行内容复制到新 DataRow
对象中,然后将该对象插入到克隆表中。
- 复制完可查询的输入表中的所有 DataRow 对象后,将
返回克隆的DataTable。如果源序列不包含任何 DataRow 对象 ,则该方法将返回一个空 DataTable。
数据绑定和 LINQ to DataSet
? LINQ to DataSet 通过提供基于表达式的
LINQ 筛选和排序,扩展了DataView 筛选 和排序的功能,它允许执行比基于字符吕 睥筛选和排序更为复杂且功能更为强大的 筛选和排序操作。
using System;
usingSystem.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
usingSystem.Data.SqlClient;
usingSystem.Globalization;
namespaceLINQtoDataSet
{
class Program
{
/// <summary>
/// 填充数据集
/// </summary>
/// <param name="ds">数据集</param>
static void FillDataSet(DataSet ds)
{
try
{
// Create a new adapter andgive it a query to fetch sales order, contact,
// address, and productinformation for sales in the year 2002. Point connection
// information to theconfiguration setting "AdventureWorks".
string connectionString ="Data Source=localhost;Initial Catalog=AdventureWorks;"
+ "Integrated Security=true;";
SqlDataAdapter da = newSqlDataAdapter(
"SELECT SalesOrderID,ContactID, OrderDate, OnlineOrderFlag, " +
"TotalDue,SalesOrderNumber, Status, ShipToAddressID, BillToAddressID " +
"FROMSales.SalesOrderHeader " +
"WHERE DATEPART(YEAR,OrderDate) = @year; " +
"SELECTd.SalesOrderID, d.SalesOrderDetailID, d.OrderQty, " +
"d.ProductID, d.UnitPrice" +
"FROMSales.SalesOrderDetail d " +
"INNER JOINSales.SalesOrderHeader h " +
"ON d.SalesOrderID =h.SalesOrderID " +
"WHERE DATEPART(YEAR,OrderDate) = @year; " +
"SELECT p.ProductID,p.Name, p.ProductNumber, p.MakeFlag, " +
"p.Color, p.ListPrice,p.Size, p.Class, p.Style, p.Weight " +
"FROMProduction.Product p; " +
"SELECT DISTINCT a.AddressID,a.AddressLine1, a.AddressLine2, " +
"a.City,a.StateProvinceID, a.PostalCode " +
"FROM Person.Address a" +
"INNER JOINSales.SalesOrderHeader h " +
"ON a.AddressID = h.ShipToAddressID ORa.AddressID = h.BillToAddressID " +
"WHERE DATEPART(YEAR,OrderDate) = @year; " +
"SELECT DISTINCTc.ContactID, c.Title, c.FirstName, " +
"c.LastName,c.EmailAddress, c.Phone " +
"FROM Person.Contact c" +
"INNER JOINSales.SalesOrderHeader h " +
"ON c.ContactID =h.ContactID " +
"WHERE DATEPART(YEAR,OrderDate) = @year;",
connectionString);
// Add table mappings.
da.SelectCommand.Parameters.AddWithValue("@year", 2002);
da.TableMappings.Add("Table", "SalesOrderHeader");
da.TableMappings.Add("Table1", "SalesOrderDetail");
da.TableMappings.Add("Table2", "Product");
da.TableMappings.Add("Table3", "Address");
da.TableMappings.Add("Table4", "Contact");
// Fill the DataSet.
da.Fill(ds);
// Add data relations.
DataTable orderHeader =ds.Tables["SalesOrderHeader"];
DataTable orderDetail =ds.Tables["SalesOrderDetail"];
DataRelation order = newDataRelation("SalesOrderHeaderDetail",
orderHeader.Columns["SalesOrderID"],
orderDetail.Columns["SalesOrderID"], true);
ds.Relations.Add(order);
DataTable contact =ds.Tables["Contact"];
DataTable orderHeader2 =ds.Tables["SalesOrderHeader"];
DataRelation orderContact = newDataRelation("SalesOrderContact",
contact.Columns["ContactID"],
orderHeader2.Columns["ContactID"],true);
ds.Relations.Add(orderContact);
}
catch (SqlException ex)
{
Console.WriteLine("SQLexception occurred: " + ex.Message);
}
}
static void Main(string[]args)
{
//Method1();
//Method2();
//Method3();
//Method4();
//Method5();
//Method6();
//Method7();
//Method8();
//Method9();
}
[STAThread()]
private static void Method9()
{
BindingForm form = newBindingForm();
form.ShowDialog();
}
/// <summary>
/// 通过查询创建数据表
/// </summary>
private static void Method8()
{
DataSet ds = new DataSet();
ds.Locale =CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable orders =ds.Tables["SalesOrderHeader"];
// Query the SalesOrderHeader tablefor orders placed
// after August 8, 2001.
IEnumerable<DataRow> query =
from order inorders.AsEnumerable()
where order.Field<DateTime>("OrderDate")> new DateTime(2001, 8, 1)
select order;
// Create a table from the query.
DataTable boundTable =query.CopyToDataTable<DataRow>();
foreach (DataRow row inboundTable.Rows)
{
Console.WriteLine("{0}\t{1}", row["SalesOrderID"],row["OrderDate"]);
}
}
/// <summary>
/// 比较DataRow
/// </summary>
private static void Method7()
{
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale =CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable contactTable =ds.Tables["Contact"];
// Create two tables.
IEnumerable<DataRow> query1 =from contact in contactTable.AsEnumerable()
wherecontact.Field<string>("Title") == "Ms."
select contact;
IEnumerable<DataRow> query2 =from contact in contactTable.AsEnumerable()
wherecontact.Field<string>("FirstName") == "Sandra"
select contact;
DataTable contacts1 =query1.CopyToDataTable();
DataTable contacts2 =query2.CopyToDataTable();
// Find the intersection of the twotables.
var contacts =contacts1.AsEnumerable().Intersect(contacts2.AsEnumerable(),
DataRowComparer.Default);
Console.WriteLine("Intersection of contacts tables");
foreach (DataRow row in contacts)
{
Console.WriteLine("Id: {0}{1} {2} {3}",
row["ContactID"],row["Title"], row["FirstName"], row["LastName"]);
}
}
/// <summary>
/// 查询类型化数据集
/// </summary>
private static void Method6()
{
AW.ProductDataTable products = newAW.ProductDataTable();
AWTableAdapters.ProductTableAdapteradapter = new LINQtoDataSet.AWTableAdapters.ProductTableAdapter();
adapter.Fill(products);
var query = from p in products
wherep.FinishedGoodsFlag == true
select new
{
p.ProductID,
p.Name,
p.ProductNumber
};
foreach (var product in query)
{
Console.WriteLine("{0}\t{1:d}\t{2}",
product.ProductID,
product.Name,
product.ProductNumber);
}
}
/// <summary>
/// 交叉表查询
/// </summary>
private static void Method5()
{
// 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 inorders.AsEnumerable()
join detail indetails.AsEnumerable()
onorder.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);
}
}
/// <summary>
/// 强制查询
/// </summary>
private static void Method4()
{
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale =CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products =ds.Tables["Product"];
IEnumerable<DataRow> query =
from product inproducts.AsEnumerable()
orderbyproduct.Field<Decimal>("ListPrice") descending
select product;
// Force immediate execution of thequery.
IEnumerable<DataRow>productsArray = query.ToArray();
Console.WriteLine("Every pricefrom highest to lowest:");
foreach (DataRow prod inproductsArray)
{
Console.WriteLine(prod.Field<Decimal>("ListPrice"));
}
}
/// <summary>
/// 延迟查询
/// </summary>
private static void Method3()
{
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale =CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products =ds.Tables["Product"];
IEnumerable<DataRow>productsQuery =
from product inproducts.AsEnumerable()
select product;
IEnumerable<DataRow>largeProducts =
productsQuery.Where(p =>p.Field<string>("Size") == "L");
Console.WriteLine("Products ofsize 'L':");
foreach (DataRow product inlargeProducts)
{
Console.WriteLine(product.Field<string>("Name"));
}
}
/// <summary>
/// 使用基于方法的查询语法
/// </summary>
private static void Method2()
{
DataSet ds = new DataSet();
ds.Locale =CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products =ds.Tables["Product"];
var query =products.AsEnumerable().
Select(product => new
{
ProductName =product.Field<string>("Name"),
ProductNumber =product.Field<string>("ProductNumber"),
Price =product.Field<decimal>("ListPrice")
});
Console.WriteLine("ProductInfo:");
foreach (var productInfo in query)
{
Console.WriteLine("Productname: {0} Product number: {1} List price: ${2} ",
productInfo.ProductName,productInfo.ProductNumber, productInfo.Price);
}
}
/// <summary>
/// 使用标准查询操作符
/// </summary>
private static void Method1()
{
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale =CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products =ds.Tables["Product"];
IEnumerable<DataRow> query =
from product inproducts.AsEnumerable()
select product;
Console.WriteLine("ProductNames:");
foreach (DataRow p in query)
{
Console.WriteLine(p.Field<string>("Name"));
}
}
}
}