1. Trang chủ
  2. » Công Nghệ Thông Tin

Using LINQ to DataSet

10 561 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Using LINQ to DataSet
Thể loại Chapter
Định dạng
Số trang 10
Dung lượng 217,95 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Chapter 18Using LINQ to DataSet After completing this chapter, you will be able to: ■ ■ Prepare a DataTable instance so that it uses the IEnumerable interface ■ ■ Treat ADO.NET table val

Trang 1

Chapter 18

Using LINQ to DataSet

After completing this chapter, you will be able to:

Prepare a DataTable instance so that it uses the IEnumerable interface

■ Treat ADO.NET table values as first-class members of a LINQ query

■ Cast type-neutral column values as strongly typed query values

LINQ processes data from a variety of sources, but those sources must first be expressed in a form that LINQ can use For instance, LINQ expects that all incoming data be stored in a

col-lection, one that conforms to either the IEnumerable(Of T) or the IQueryable(Of T) interface The LINQ to DataSet provider endows ordinary ADO.NET DataTable objects with the ability

to participate fully in LINQ queries It does this by adding the necessary LINQ requirements

to relevant ADO.NET classes This chapter introduces these enhancements and shows you how to employ them to extract data from data sets using the power of LINQ

Understanding the LINQ to DataSet Provider

ADO.NET’s DataTable class, as a logical collection of data-laden objects, is the perfect

can-didate for inclusion in LINQ queries Unfortunately, it exhibits two aspects that make it less

than useful with LINQ: (1) it implements neither IEnumerable(Of T) nor IQueryable(Of T), and (2) the data values contained in each DataRow instance exist as System.Object instances and only indirectly express their true types through DataColumn definitions.

To overcome these deficiencies, the LINQ to DataSet provider adds new extension methods

to both the DataTable and DataRow classes These new features appear in the System.Data DataSetExtensions assembly (found in the System.Data.DataSetExtensions.dll library file) The assembly defines two classes, DataTableExtensions and DataRowExtensions, that include new extension methods for the DataTable and DataRow classes, respectively For data tables, there is a new AsQueryable method that acts as the gateway for bringing ADO.NET data into

a LINQ query

Trang 2

neric, semi-typeless existence to a strongly typed presence within your queries It is still up

to you, as the programmer, to correctly indicate the type of each field as you add them to the LINQ query syntax But once defined, you can apply all the standard operators to those fields, including them in projections, filters, and other types of expressions

Note You can use DataRow values within LINQ queries without applying the Field(Of T) exten-sion method However, these fields will still pose as System.Object instances This might prevent

you from carrying out certain types of query actions on specific fields Also, you must still resolve the data type of each field before using it in post-query processing.

LINQ to DataSet also lets you craft queries that use ADO.NET Typed Data Sets; however, the

Entity Framework supercedes most of the advantages of typed data sets Therefore, LINQ queries against typed data sets are not discussed in this book

Writing Queries with LINQ to DataSet

With the exception of the new enumerated methods specific to LINQ to DataSet, using

ADO.NET DataTable objects in LINQ queries is identical to using standard collection objects The first step involves converting a data table to its enumerable equivalent using the and, which can be applied to any DataTable instance.

C#

// - Customer is an existing DataTable instance.

var results = from cu in Customer.AsEnumerable()

select cu;

Visual Basic

' - Customer is an existing DataTable instance.

Dim results = From cu In Customer.AsEnumerable()

Select cu

Although the LINQ to DataSet provider includes “DataSet” in its name, the focus in LINQ

queries is on the DataTable class LINQ to DataSet does not consider a DataTable instance’s presence in an overall DataSet to be significant, nor does it examine any DataRelationship objects when processing queries that contain multiple DataTable instances You must link tables together using LINQ’s standard Join operator or use the Where clause to create an

implicit join

Trang 3

Chapter 18 Using LINQ to DataSet 307

C#

// - Explicit join.

var results = from cu in Customer.AsEnumerable()

join ord in Order.AsEnumerable() on cu.ID equals ord.CustomerID

select

// - Implicit join

var results = from cu in Customer.AsEnumerable()

from ord in Order.AsEnumerable()

where cu.ID == ord.CustomerID

select

Visual Basic

' - Explicit join.

Dim results = From cu In Customer.AsEnumerable()

Join ord In Order.AsEnumerable() On cu.ID Equals ord.CustomerID

Select

' - Implicit join

Dim results = From cu In Customer.AsEnumerable(), ord In Order.AsEnumerable()

Where cu.ID = ord.CustomerID

Select

After making the tables part of the query, you can access each row’s individual column values

as if they were typical LINQ query properties As mentioned previously, LINQ will not auto-matically ascertain the data type of any given column; you must explicitly cast each field to its proper type

To cast a field, add the Field extension method to the end of the range variable (the range variables in the previous code sample are cu and ord) Because the implementation of Field

uses generics, you must also attach a type name using the language-appropriate syntax Pass

the name of the column as an argument to Field.

C#

var results = from cu in Customer.AsEnumerable()

orderby cu.Field<string>("FullName")

select new { CustomerName = cu.Field<string>("FullName") };

Visual Basic

Dim results = From cu In Customer.AsEnumerable()

Select CustomerName = cu.Field(Of String)("FullName")

Order By CustomerName

Trang 4

The Field method includes a few overloaded variations In addition to field names, you can

use a zero-based column position to locate field data, although this might reduce readability

in your queries An additional argument lets you specify the DataRowVersion to use By de-fault, queries use the DataRowVersion.Current version of the row.

Even when enumerated DataTable objects play a key role in a LINQ query, they need not be

the only source of data involved Part of LINQ’s appeal is that it allows you to write queries that involve data from disparate sources You can mix LINQ to Objects and LINQ to DataSet

content in the same query simply by including each source in the From clause.

C#

// - Build an ad hoc collection, although you could also

// include a fully realized class.

var statusTable[] = { new { Code = "P", Description = "Active Order" },

new { Code = "C", Description = "Completed / Shipped" },

new { Code = "X", Description = "Canceled" }};

// - Link ADO.NET and Object collections in one query.

var results = from ord in Order.AsEnumerable()

join sts in statusTable on

ord.Field<string>("StatusCode") equals sts.Code

orderby ord.Field<long>("ID")

select new { OrderID = ord.Field<long>("ID"),

CurrentStatus = sts.Description };

Visual Basic

' - Build an ad hoc collection, although you could also

' include a fully realized class.

Dim statusTable = {New With {.Code = "P", Description = "Active Order"},

New With {.Code = "C", Description = "Completed / Shipped"},

New With {.Code = "X", Description = "Canceled"}}

' - Link ADO.NET and Object collections in one query.

Dim results = From ord In Order.AsEnumerable()

Join sts In statusTable On _

ord.Field(Of String)("StatusCode") Equals sts.Code

Select OrderID = ord.Field(Of Long)("ID"),

CurrentStatus = sts.Description

Order By OrderID

As in LINQ to Objects, the actual processing of a LINQ to DataSet query does not occur until

your code references content from a constructed query However, all the involved DataTable

Trang 5

Chapter 18 Using LINQ to DataSet 309

with data from external sources, you must bring any data you plan to include in a LINQ

query into the relevant DataTable instances before passing the objects through LINQ If you use a DataAdapter to load data, call its Fill method before using LINQ to extract data.

Note The DataAdapter object’s Fill method loads all requested data into local DataSet memory

If the tables you need to query with LINQ are large and you aren’t able to first reduce the num-ber of ADO.NET-managed rows, you might wish to consider alternatives to LINQ to DataSet LINQ to Entities, discussed in Chapter 19, “Using LINQ to Entities,” can process external data without the need to load full tables into memory.

Querying with LINQ to DataSet: C#

1 Open the “Chapter 18 CSharp” project from the installed samples folder The project

includes a Windows.Forms class named OrderViewer, which is a simple order-list viewer.

2 Open the source code view for the OrderViewer form Locate the GetConnectionString

function; this is a routine that uses a SqlConnectionStringBuilder to create a valid

con-nection string to the sample database It currently includes the following statements: sqlPortion.DataSource = @"(local)\SQLExpress";

sqlPortion.InitialCatalog = "StepSample";

sqlPortion.IntegratedSecurity = true;

Adjust these statements as needed to provide access to your own test database

3 Locate the ActView_Click event handler This routine displays a list of orders for either

all customers in the database or for a specific customer by ID number Just after the

“Retrieve all customer orders” comment, add the following statement:

var result = from cu in customerTable.AsEnumerable()

from ord in orderTable.AsEnumerable()

from sts in statusTable

where cu.Field<long>("ID") == ord.Field<long>("Customer")

&& ord.Field<string>("StatusCode") == sts.Code

orderby cu.Field<string>("FullName"), ord.Field<long>("ID")

select new { CustomerID = cu.Field<long>("ID"),

CustomerName = cu.Field<string>("FullName"),

OrderID = ord.Field<long>("ID"),

OrderStatus = sts.Description,

OrderDate = ord.Field<Date>("OrderDate"),

OrderTotal = ord.Field<decimal>("Total") };

This query combines two DataTable instances (customerTable and orderTable, each decorated with the AsEnumerable extension method) with a collection of local object instances (statusTable) It forms implicit inner joins between the tables via the where

clause and performs a projection of fields from each source table

Trang 6

4 Just after the “Filter and display the orders” comment, add the following lines:

var result2 = result.Where(ord => ord.CustomerID ==

long.Parse(CustomerID.Text));

AllOrders.DataSource = result2.ToList();

These statements filter the original query by selecting those records that include a user-specified customer ID This segment uses LINQ extension methods and a lambda ex-pression, which works well with the LINQ to DataSet provider The second line displays the results

5 Just after the “Just display the original full results” comment, add the following

statement:

AllOrders.DataSource = result.ToList();

This code displays the query results when no further customer ID filtering is needed

6 Run the program To see orders, select the Include One Customer By ID option, enter 1

in the Customer ID field, and then click View

The grid displays content from each of the three source tables For example, the

CustomerName column shows a value from the ADO.NET Customer table, the

OrderDate column comes from the Order table, and OrderStatus gets its information from the ad hoc in-memory statusTable collection.

Querying with LINQ to DataSet: Visual Basic

1 Open the “Chapter 18 VB” project from the installed samples folder The project

in-cludes a Windows.Forms class named OrderViewer, which is a simple order-list viewer.

Trang 7

Chapter 18 Using LINQ to DataSet 311

2 Open the source code view for the OrderViewer form Locate the GetConnectionString

function; this is a routine that uses a SqlConnectionStringBuilder to create a valid

con-nection string to the sample database It currently includes the following statements: sqlPortion.DataSource = "(local)\SQLExpress"

sqlPortion.InitialCatalog = "StepSample"

sqlPortion.IntegratedSecurity = True

Adjust these statements as needed to provide access to your own test database

3 Locate the ActView_Click event handler This routine displays a list of orders for either

all customers in the database or for a specific customer by ID number Just after the

“Retrieve all customer orders” comment, add the following statement:

Dim result = From cu In customerTable.AsEnumerable(),

ord In orderTable.AsEnumerable(),

sts In statusTable

Where cu.Field(Of Long)("ID") = ord.Field(Of Long)("Customer") _

And ord.Field(Of String)("StatusCode") = sts.Code

Select CustomerID = cu.Field(Of Long)("ID"),

CustomerName = cu.Field(Of String)("FullName"),

OrderID = ord.Field(Of Long)("ID"),

OrderStatus = sts.Description,

OrderDate = ord.Field(Of Date)("OrderDate"),

OrderTotal = ord.Field(Of Decimal)("Total")

Order By CustomerName, OrderID

This query combines two DataTable instances (customerTable and orderTable, each decorated with the AsEnumerable extension method) with a collection of local object instances (statusTable) It forms implicit inner joins between the tables via the Where

clause and performs a projection of fields from each source table

4 Just after the “Filter and display the orders” comment, add the following lines:

Dim result2 = result.Where(Function(ord) ord.CustomerID =

CLng(CustomerID.Text))

AllOrders.DataSource = result2.ToList()

These statements filter the original query by selecting those records that include a user-specified customer ID This segment uses LINQ extension methods and a lambda ex-pression, which works well with the LINQ to DataSet provider The second line displays the results

5 Just after the “Just display the original full results” comment, add the following

statement:

AllOrders.DataSource = result.ToList()

This code displays the query results when no further customer ID filtering is needed

Trang 8

6 Run the program To see orders, select the Include All Customers option and then click

View

The grid displays content from each of the three source tables For example, the

CustomerName column shows a value from the ADO.NET Customer table, the OrderDate column comes from the Order table, and OrderStatus gets its information from the ad hoc in-memory statusTable collection.

Summary

This chapter introduced LINQ to DataSet, an ADO.NET-focused variation of LINQ to Objects The implementation of the LINQ to Dataset provider shares a close relationship and syntax with the base LINQ to Objects implementation By applying a few simple extension methods,

DataTable objects can become part of independent or integrated data queries.

Beyond LINQ to Objects, LINQ to DataSet is probably the easiest of the LINQ providers to use in your application Its only drawback is that it expects any queried data to be memory-resident, something not required by other LINQ providers that extract content from external databases

Trang 9

Chapter 18 Using LINQ to DataSet 313

Chapter 18 Quick Reference

Include a DataTable instance in a LINQ query Call the DataTable object’s AsEnumerable extension

method.

Pass the results of this call as a table source in the query.

Include a DataTable column in a LINQ query Add the DataTable as a source within the query, adding a

range variable.

Call the range variable’s Field extension method,

indicat-ing the generic data type and the name of the column.

Ngày đăng: 03/10/2013, 00:20

TỪ KHÓA LIÊN QUAN

w