Linq to DataSet
1.数据集( DataSet )
• DataSet 是更为广泛使用的ADO.NET 组件之一,它可以显式缓存不同数据源中的数据。
• 在表示层上DataSet 与GUI 控件紧密集成,以进行数据绑定。
• 在中间层上,它提供保留数据关系形状的缓存并包括快速简单查询和层次结构导航服务,从而可以减少对数据库的请求数。
2.查询数据集
• DataSet 虽然具有突出的优点,但其查询功能也存在限制。
• Select 方法可用于筛选和排序,GetChildRows和GetParentRow 方法可用于层次结构导航。
• 但对于更复杂的情况,开发人员必须编写自定义查询。这会使应用程序性能低下并且难以维护。
3.使用LINQ to DataSet
• 使用LINQ to DataSet 可以更快更容易地查询在DataSet 对象中缓存的数据。
• 这些查询用编程语言本身表示,而不表示为嵌入在应用程序代码中的字符串。
• LINQ to DataSet 可使Visual Studio 开发人员的工作效率更高,
因为Visual Studio IDE 提供编译时语法检查、静态类型化和对 LINQ 的智能感知的支持。
• LINQ to DataSet 也可用于查询从一个或多个数据源合并的数据 这可以使许多需要灵活表示和处理数据的方案能够实现。
4.查询数据集
• 填充DataSet
– XxxDataAdapter
– LINQ to SQL
•主要使用下面两个扩展类
– DataRowExtensions
– DataTableExtensions
• 查询支持
– 类型化数据集
– 非类型化数据集
5.启用LINQ to DataSet 功能
• 要求.NET Framework 3.5
• 引用System Data DataSetExtensions 程序集
6.使用标准查询运算符
• 可以使用下面LINQ标准查询运算符
– from
– where
– select
7.基于方法的查询语法
• 表述LINQ to DataSet 查询的另一种方法
• 是对LINQ 运算符方法的一系列直接方法调用
• 需要将Lambda 表达式作为参数进行传递
8.延迟查询
• 当查询旨在返回一系列值时,查询变量本身只存储查询命令
• 如果查询不包含可使查询立即执行的方法,则查询的实际执行将会推迟直到在foreach 或For Each 循环中循环访问查询变量。
• 延迟执行可使多个查询组合在一起或使查询得到扩展。
9.主动查询
• 使用下列方法可以进行主动查询:
– ToList<TSource>
– ToArray<TSource>
– ToLookup
– ToDictionary
10.交叉表查询
•LINQ提供两个联接运算符
– Join :对于关系数据库,Join 实现内部联接。
– GroupJoin:对于关系数据库,GroupJoin 运算符没有直接等效项,它们实现内部联接和左外部联接的超集。
• 这些运算符执行同等联接,即仅在键相等时匹配两个数据源的联接。
11.查询类型化数据集
• 对于类型化DataSet,不必使用泛型Field方法或SetField 方法即可访问列数据。
• 由于DataSet 中包括类型信息,因此属性名称在编译时可用。
• LINQ to DataSet 提供对正确类型的列值的访问,以便可以在编译代码时而不是在运行时捕获类型不匹配错误。
12.比较DataRow
•LINQ定义多种用于比较源元素的集合运算符以查看它们是否相等
– Distinct:返回序列中的非重复元素
– Union:生成两个序列的并集
– Intersect :生成两个序列的交集
– Except:生成两个序列的差集
• 这些运算符通过对每个元素集合调用GetHashCode和Equals 方法来比较源元素。
13.通过查询创建数据表
• CopyToDataTable 方法
• 它使用下面的过程通过查询创建 DataTable
– CopyToDataTable方法克隆源表中的DataTable
– 克隆的DataTable 的架构从源表中枚举的第一个DataRow对象的列生成,克隆表的名称是源表的名称
后面追加单词“query” 。
– 对于源表中的每一行,会将行内容复制到新DataRow对象中,然后将该对象插入到克隆表中。
– 复制完可查询的输入表中的所有DataRow对象后,将返回克隆的DataTable。如果源序列不包含任何
DataRow对象则该方法将返回一个空DataTable DataRow对象,则该方法将返回 个空DataTable。
14.数据绑定和LINQ to DataSet
• LINQ to DataSet 通过提供基于表达式的LINQ 筛选和排序,扩展了DataView筛选和排序的功能,
它允许执行比基于字符串筛选和排序更为复杂且功能更为强大的筛选和排序操作。
代码如下:
class Program { /// <summary> /// 填充数据集 /// </summary> /// <param name="ds">数据集</param> static void FillDataSet(DataSet ds) { try { // Create a new adapter and give it a query to fetch sales order, contact, // address, and product information for sales in the year 2002. Point connection // information to the configuration setting "AdventureWorks". string connectionString = "Data Source=localhost;Initial Catalog=AdventureWorks;" + "Integrated Security=true;"; SqlDataAdapter da = new SqlDataAdapter( "SELECT SalesOrderID, ContactID, OrderDate, OnlineOrderFlag, " + "TotalDue, SalesOrderNumber, Status, ShipToAddressID, BillToAddressID " + "FROM Sales.SalesOrderHeader " + "WHERE DATEPART(YEAR, OrderDate) = @year; " + "SELECT d.SalesOrderID, d.SalesOrderDetailID, d.OrderQty, " + "d.ProductID, d.UnitPrice " + "FROM Sales.SalesOrderDetail d " + "INNER JOIN Sales.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 " + "FROM Production.Product p; " + "SELECT DISTINCT a.AddressID, a.AddressLine1, a.AddressLine2, " + "a.City, a.StateProvinceID, a.PostalCode " + "FROM Person.Address a " + "INNER JOIN Sales.SalesOrderHeader h " + "ON a.AddressID = h.ShipToAddressID OR a.AddressID = h.BillToAddressID " + "WHERE DATEPART(YEAR, OrderDate) = @year; " + "SELECT DISTINCT c.ContactID, c.Title, c.FirstName, " + "c.LastName, c.EmailAddress, c.Phone " + "FROM Person.Contact c " + "INNER JOIN Sales.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 = new DataRelation("SalesOrderHeaderDetail", orderHeader.Columns["SalesOrderID"], orderDetail.Columns["SalesOrderID"], true); ds.Relations.Add(order); DataTable contact = ds.Tables["Contact"]; DataTable orderHeader2 = ds.Tables["SalesOrderHeader"]; DataRelation orderContact = new DataRelation("SalesOrderContact", contact.Columns["ContactID"], orderHeader2.Columns["ContactID"], true); ds.Relations.Add(orderContact); } catch (SqlException ex) { Console.WriteLine("SQL exception occurred: " + ex.Message); } } static void Main(string[] args) { //Method1(); //Method2(); //Method3(); //Method4(); //Method5(); //Method6(); //Method7(); //Method8(); //Method9(); } [STAThread()] private static void Method9() { BindingForm form = new BindingForm(); 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 table for orders placed // after August 8, 2001. IEnumerable<DataRow> query = from order in orders.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 in boundTable.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() where contact.Field<string>("Title") == "Ms." select contact; IEnumerable<DataRow> query2 = from contact in contactTable.AsEnumerable() where contact.Field<string>("FirstName") == "Sandra" select contact; DataTable contacts1 = query1.CopyToDataTable(); DataTable contacts2 = query2.CopyToDataTable(); // Find the intersection of the two tables. 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 = new AW.ProductDataTable(); AWTableAdapters.ProductTableAdapter adapter = new LINQtoDataSet.AWTableAdapters.ProductTableAdapter(); adapter.Fill(products); var query = from p in products where p.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 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); } } /// <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 in products.AsEnumerable() orderby product.Field<Decimal>("ListPrice") descending select product; // Force immediate execution of the query. IEnumerable<DataRow> productsArray = query.ToArray(); Console.WriteLine("Every price from highest to lowest:"); foreach (DataRow prod in productsArray) { 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 in products.AsEnumerable() select product; IEnumerable<DataRow> largeProducts = productsQuery.Where(p => p.Field<string>("Size") == "L"); Console.WriteLine("Products of size 'L':"); foreach (DataRow product in largeProducts) { 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("Product Info:"); foreach (var productInfo in query) { Console.WriteLine("Product name: {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 in products.AsEnumerable() select product; Console.WriteLine("Product Names:"); foreach (DataRow p in query) { Console.WriteLine(p.Field<string>("Name")); } } }