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

Using LINQ to Entities

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

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Using LINQ to Entities
Trường học Unknown University
Chuyên ngành Computer Science
Thể loại Document
Năm xuất bản Unknown Year
Thành phố Unknown City
Định dạng
Số trang 16
Dung lượng 345,89 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 19Using LINQ to Entities After completing this chapter, you will be able to: ■ ■ Create LINQ queries that access content from an Entity Framework data model ■ ■ Call database-lev

Trang 1

Chapter 19

Using LINQ to Entities

After completing this chapter, you will be able to:

■ Create LINQ queries that access content from an Entity Framework data model

■ Call database-level functions from LINQ queries

■ Understand how LINQ treats entities differently from other data sources

The Entity Framework (EF) is a model-based interface between your application and an ex-ternal database As discussed earlier in this book, the Framework presents logical, database-centric data content in a conceptual form expressed through object instances This focus on objects makes the Entity Framework a great match for LINQ

The LINQ to Entities provider brings the world of entities and LINQ queries together This chapter introduces this EF-centric LINQ provider, a system that takes advantage of the Entity Framework’s model-focused data and LINQ’s capability to develop native language queries that target entities and their properties

Note The exercises in this chapter all use the same sample project, a tool that makes queries using LINQ to Entities Although you can run the application after each exercise, the expected results for the full application might not appear until you complete all exercises in the chapter.

Understanding the LINQ to Entities Provider

The ObjectSet(Of TEntity) and ObjectQuery(Of T) classes—the two key collection-style base

classes used in the Entity Framework—are ready to use in LINQ queries Both collection

types implement IEnumerable(Of T) and IQueryable(Of T), the same interfaces that LINQ

requires to enable query operations on a collection Any entity collection exposed by an EF

context or built from an ObjectQuery instance—such as a query processed with Entity SQL—

can form the basis of a LINQ query

EF entities referenced in a LINQ query expose properties that are available for projection, filtering, sorting, and other LINQ operations LINQ to Entities queries are much cleaner than their LINQ to DataSet counterparts because each entity property already expresses its model-defined data type

Trang 2

(from the database) does not occur at the time you build a data query; instead, data is pro-cessed and returned to your application only when you attempt to reference specific entities and properties When you write an EF query, the Framework prepares a T-SQL query (when SQL Server is used as the backend database) that it runs on the database server to obtain the desired records That database action occurs only when you access the results of the query statement

When you craft LINQ queries that involve EF objects, the application employs this same form

of delayed processing The clauses in a LINQ query—and ultimately the extension methods and lambda expressions that make up a LINQ expression tree—translate into SQL statements

and clauses that are played out on the data server For this reason, all LINQ to Entities queries can involve only objects and data elements that can be represented within a remotely run SQL statement While other LINQ providers can be mixed—Chapter 18, “Using LINQ to DataSet,”

combined LINQ to Objects and LINQ to DataSet content—LINQ to Entities imposes restric-tions on the type of data involved in the queries

Note One of the exercises in this chapter will demonstrate one way that LINQ to Entities can be used indirectly with other forms of LINQ.

Some LINQ features available with other LINQ providers are not supported by LINQ to Entities Projections, comparisons, and joins that are based on a locally-defined function won’t work in LINQ to Entities because the local function cannot be represented in a SQL

query running elsewhere Also, the Last, SkipWhile, and TakeWhile extension methods are not available; Skip and Take (in both their SQL-style and extension method forms) will work.

Writing Queries with LINQ to Entities

As with all LINQ providers, the general structure of LINQ to Entities queries varies only a little from the LINQ to Objects standard In fact, looking at a LINQ to Entities query, it’s hard to see that it isn’t working with standard NET objects The telltale sign is the use of an active Entity Framework object context, either as a direct source for entities or as a way to run an

ObjectQuery that will feed data into LINQ.

Trang 3

Here is a query that returns some properties from a Customer entity:

C#

using (SalesOrderEntities context = new SalesOrderEntities(connectionString))

{

var results = from cu in context.Customers

orderby cu.FullName

select new { CustomerID = cu.ID, CustomerName = cu.FullName };

}

Visual Basic

Using context As New SalesOrderEntities(connectionString)

Dim results = From cu In context.Customers

Order By cu.FullName

Select CustomerID = cu.ID, CustomerName = cu.FullName

End Using

Most of the standard LINQ clauses are included, in both their LINQ expression and their

extension method/lambda expression forms, including Where, Join, Group By, and so on

As far as the LINQ syntax is concerned, LINQ to Entities is pretty full-featured But there are

limitations Some, such as the inability to use the SkipWhile and TakeWhile extension meth-ods, were listed previously Others follow this general rule: If it can’t be converted easily into a storage-level function, it can’t be used directly in LINQ to Entities.

Querying with LINQ to Entities: C#

Note This exercise parallels the exercise found in Chapter 18 It is nearly identical in functionality and purpose, but uses LINQ to Entities instead of LINQ to DataSet to process database content.

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

includes three Windows.Forms classes: OrderViewer, StatesByYear, and Switchboard This example focuses on the OrderViewer form.

Trang 4

2 Open the source code view for the General class Locate the GetConnectionString

func-tion; this is a routine that uses a SqlConnectionStringBuilder to create a valid connection

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 Open the source code view for the OrderViewer form Locate the ActView_Click event

handler This routine displays a list of orders, either for all customers in the database or for a specific customer by ID number Just after the “Retrieve all customer orders” com-ment, add the following statement:

var result = from cu in OrderContext.Customers

from ord in OrderContext.OrderEntries

where cu.ID == ord.Customer

orderby cu.FullName, ord.ID

select new { CustomerID = cu.ID,

CustomerName = cu.FullName,

OrderID = ord.ID,

OrderDate = ord.OrderDate,

OrderTotal = ord.Total,

ord.StatusCode };

This query combines two entity collections, Customers and OrderEntries, both of which are members of the SalesOrderEntities class, a derived Entity Framework context It forms implicit inner joins between the entity collections via the where clause and

per-forms a sorted projection of fields from each source table

4 Just after the “Add in the status code” comment, add the following query:

var result2 = from cu in result.ToArray()

from sts in statusTable

where cu.StatusCode == sts.Code

select new { cu.CustomerID, cu.CustomerName, cu.OrderID,

OrderStatus = sts.Description, cu.OrderDate, cu.OrderTotal };

This query extends the original query by linking in a local object collection This is nec-essary because LINQ to Entities cannot transmit an entire local collection to the data-base for SQL processing Instead, the original query must be converted into a regular

.NET collection, as is done with the result.ToArray() clause The original query is

pro-cessed at that moment, and the results are placed in a standard anonymous array The

result2 query is actually doing its work using LINQ to Objects.

Trang 5

5 Run the program When the Switchboard form appears, click Order Viewer When the

OrderViewer form appears, select the Include All Customers option and then click View.

The grid displays content from the Customer and OrderEntries entities, plus a column from the local statusTable collection.

Querying with LINQ to Entities: Visual Basic

Note This exercise parallels the exercise found in Chapter 18 It is nearly identical in functionality and purpose, but uses LINQ to Entities instead of LINQ to DataSet to process database content.

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

in-cludes three Windows.Forms classes: OrderViewer, StatesByYear, and Switchboard This example focuses on the OrderViewer form.

2 Open the source code view for the General module 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

Trang 6

3 Open the source code view for the OrderViewer form Locate the ActView_Click event

handler This routine displays a list of orders, either for all customers in the database or for a specific customer by ID number Just after the “Retrieve all customer orders” com-ment, add the following statement:

Dim result = From cu In OrderContext.Customers,

ord In OrderContext.OrderEntries

Where cu.ID = ord.Customer

Select CustomerID = cu.ID,

CustomerName = cu.FullName,

OrderID = ord.ID,

OrderDate = ord.OrderDate,

OrderTotal = ord.Total,

ord.StatusCode

Order By CustomerName, OrderID

This query combines two entity collections, Customers and OrderEntries, both of which are members of the SalesOrderEntities class, a derived Entity Framework context It forms implicit inner joins between the entity collections via the Where clause and

per-forms a sorted projection of fields from each source table

4 Just after the “Add in the status code” comment, add the following query:

Dim result2 = From cu In result.ToArray(), sts In statusTable

Where cu.StatusCode = sts.Code

Select cu.CustomerID, cu.CustomerName, cu.OrderID,

OrderStatus = sts.Description, cu.OrderDate, cu.OrderTotal

This query extends the original query by linking in a local object collection This is nec-essary because LINQ to Entities cannot transmit an entire local collection to the database for SQL processing Instead, the original query must be converted into a regular NET

collection, as is done with the result.ToArray() clause The original query is processed

at that moment and the results are placed in a standard anonymous array The result2

query is actually doing its work using LINQ to Objects

5 Run the program When the Switchboard form appears, click Order Viewer When the OrderViewer form appears, select the Include One Customer By ID option, enter 1 in

the Customer ID field and then click View

Trang 7

The grid displays content from the Customer and OrderEntries entities, plus a column from the local statusTable collection.

Working with Entity and Database Functions

Calling your own custom function within the Where clause isn’t supported.

C#

private decimal? AdjustTotal(decimal? origValue)

{

// - Add tax to the amount.

if (origValue.HasValue == false) return new decimal?();

return Math.Round((decimal)origValue * LocalTaxRate, 2);

}

// - Later, try this code, although it will fail.

var result = from ord in context.OrderEntries

where AdjustTotal(ord.Total) > 500M

select new { ord.ID, ord.OrderCustomer.FullName, ord.Total };

Visual Basic

Private Function AdjustTotal(ByVal origValue As Decimal?) As Decimal?

' - Add tax to the amount.

If (origValue.HasValue = False) Then Return New Decimal?

Return Math.Round(CDec(origValue) * LocalTaxRate, 2)

End Function

' - Later, try this code, although it will fail.

Dim result = From ord In context.OrderEntries

Where AdjustTotal(ord.Total) > 500@

Select ord.ID, ord.OrderCustomer.FullName, ord.Total

Trang 8

But converting this code to use the calculation inline does work.

C#

// - This will work.

var result = from ord in context.OrderEntries

where Math.Round(ord.Total * LocalTaxRate, 2) > 500M

select new { ord.ID, ord.OrderCustomer.FullName, ord.Total };

Visual Basic

' - This will work.

Dim result = From ord In context.OrderEntries

Where Math.Round(ord.Total * LocalTaxRate, 2) > 500@

Select ord.ID, ord.OrderCustomer.FullName, ord.Total

This works because although LINQ to Entities cannot easily migrate your custom and possibly

complex AdjustTotal function to a SQL equivalent, it does know how to convert the Math Round reference into something that the database engine will recognize (the T-SQL ROUND

function)

Only certain NET methods have database-level equivalents, and it’s not always immedi-ately clear which local methods will be passed to the database without your interaction

Math.Round converts to SQL Server’s ROUND, but Math.Sqrt generates an error, even though Transact-SQL includes a SQRT function.

If you would like to have a little more confidence when writing your LINQ to Entities queries, you can forgo the automated conversion and decide up front which Entity Framework or database-level functions you want to include in your query

LINQ to Entities includes a set of canonical functions which are all hosted in the System.Data Objects.EntityFunctions class These functions somewhat parallel the Entity SQL canonical

functions discussed in the “Using Literals, Operators, and Expressions” section on page 249 of Chapter 15, although only a subset is available with LINQ

Date and time functions All the Add functions (such as AddMinutes) are included,

as are Diff functions that return an integral time span CreateTime, CreateDateTime, and CreateDateTimeOffset build new date and time values from their components TruncateTime maps to the Entity SQL Truncate function, which returns a date with the

time portion removed

String functions Left and Right return string subsets Reverse returns the content of a

string in reverse order AsUnicode and AsNonUnicode perform Unicode-related

conver-sions on existing strings These two functions are specific to LINQ to Entities and do not have Entity SQL equivalents

Trang 9

Math and statistical functions The Truncate canonical function performs

nu-meric rounding Three statistical functions—StandardDeviation, Var, and VarP are also

included

To use the canonical functions, be sure to have a using (C#) or Imports (Visual Basic) ref-erence to System.Data.Objects and then prefix the function calls in your query with the EntityFunctions class name.

C#

var result = from cu in context.Customers

where EntityFunctions.Left(cu.FullName, 1) == "A"

select cu;

Visual Basic

Dim result = From cu In context.Customers

Where EntityFunctions.Left(cu.FullName, 1) = "A"

Select cu

Beyond the canonical functions, LINQ to Entities also exposes database-level functions The

SQL Server functions appear in the System.Data.Objects.SqlClient.SqlFunctions class and

par-allel their T-SQL counterparts The following list touches lightly on the functions available

Server identity functions HostName, CurrentUser, and UserName equate to the

T-SQL HOST_NAME, CURRENT_USER, and USER_NAME functions, respectively.

Math functions Most, but not all the native SQL Server math functions are

in-cluded: Acos, Asin, Atan, Atan2, Cos, Cot, Degrees, Exp, Log, Log10, Pi, Radians, Rand, Sign, Square, SquareRoot (a renaming of SQRT), and Tan Missing from this list are ABS, CEILING, FLOOR, POWER, and ROUND, although each of these can be accomplished either by using their System.Math or EntityFunctions equivalents.

String functions Various string and string-conversion functions from SQL Server can

be called from LINQ: Ascii, Char, CharIndex, Difference (a Soundex-related function), IsDate, IsNumeric, NChar, PatIndex, QuoteName, Replicate, SoundCode (more Soundex), Space, StringConvert (known as STR in T-SQL), Stuff, and Unicode.

Date and time functions This set includes some of the query-level and system-level

date-related functions: CurrentTimestamp (known as CURRENT_TIMESTAMP in the da-tabase), DateAdd, DateDiff, DateName, DatePart, GetDate, and GetUtcDate.

Other functions The Checksum and DataLength functions map to their CHECKSUM

and DATALENGTH function counterparts in SQL Server.

The database functions work just like the canonical functions First include an Imports (Visual Basic) or using (C#) reference to System.Data.Objects.SqlClient and then attach the SqlFunctions class name to the start of each database function used in your query.

Trang 10

var result = from ord in context.OrderEntries

select new { ord.ID, ord.OrderCustomer.FullName,

LateDate = SqlFunctions.DateAdd("day", 90, ord.OrderDate) };

Visual Basic

Dim result = From ord In context.OrderEntries

Select ord.ID, ord.OrderCustomer.FullName,

LateDate = SqlFunctions.DateAdd("day", 90, ord.OrderDate)

Working with Custom Database Functions

In addition to calling database-supplied functions from your LINQ queries, you can also call

user-defined functions added to SQL Server with the CREATE FUNCTION command Like

standard stored procedures, custom functions let you add business logic within the database with standard Transact-SQL syntax, or with Visual Basic or C# via SQL Server’s support for the Common Language Runtime (CLR)

Making direct calls to database-level functions through a LINQ to Entities query involves four distinct steps:

1 Create the target function in SQL Server using the CREATE FUNCTION DDL command

Make note of the exact spelling and capitalization of the function name and its param-eters because you will need to replicate them within your application The exercise

shown later in this section references AdmittedInYear, a custom function from the

book’s sample database Here is its T-SQL definition:

CREATE FUNCTION AdmittedInYear(@whichDate AS DATETIME)

RETURNS int AS

BEGIN

- Return the number of states admitted to the union

during the year of the specified date

DECLARE @result int;

SELECT @result = COUNT(*) FROM StateRegion

WHERE DATEPART(year, Admitted) = DATEPART(year, @whichDate);

RETURN @result;

END

This function returns a count of the number of states admitted to the United States during the year specified by the supplied date

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

TỪ KHÓA LIÊN QUAN

w