The Entity Framework includes two key ways of using Entity SQL queries to access entity-managed data: using an ObjectQuery instance to query the entities within the context directly or
Trang 1The Entity Framework includes two key ways of using Entity SQL queries to access
entity-managed data: using an ObjectQuery instance to query the entities within the context directly
or using a more traditional ADO.NET provider-like interface
Running Queries Using an ObjectQuery
The System.Data.Objects.ObjectQuery(Of T) class-processes an Entity SQL statement against
an open EF context and returns the results as a collection of either named or anonymous instances
C#
// - SalesOrderEntities is an Entity Container.
using (SalesOrderEntities context =
new SalesOrderEntities(GetConnectionString()))
{
ObjectQuery<Customer> query =
New ObjectQuery<Customer>(sqlText, context);
// Other code as needed
}
Visual Basic
' - SalesOrderEntities is an Entity Container.
Using context As New SalesOrderEntities(GetConnectionString())
Dim query As New ObjectQuery(Of Customer)(sqlText, context)
' Other code as needed
End Using
You must keep the context around as long as you need to access the ObjectQuery object’s
data, especially if the retrieved data includes content accessed through a navigation property
The generic ObjectQuery type works like a typical generic collection object, but it’s not a true collection When you create the ObjectQuery instance, the Entity Framework delays
process-ing of the query until you specifically request data Even then, it might decide to retrieve only the requested portion of the data Keeping the context around during the entire
data-retrieval process enables the ObjectQuery to fulfill any data requests you give it over time.
Trang 2Note The object context and its related entity container in the conceptual model expose
a LazyLoadingEnabled property Changing this Boolean value alters the way that the Entity
Framework loads data at the other end of a navigation property Models built with the visual
de-signer set this property to True by default, keeping unused navigation property data unloaded Setting this value to False (the default for manually created models) provides more proactive
loading of related data and might allow you to access such data even when the context is no longer available You can adjust this property’s value in the visual designer or within the context instance.
The preceding code creates an instance of ObjectQuery with a generic focus of Customer,
presumably one of the entities in the Entity Data Model The Entity SQL statement used to retrieve the results must generate entities of that type Your code can also generate data val-ues not tied to any predefined entity or custom type These anonymous-type queries use the
System.Data.Common.DbDataRecord class as the target generic type.
C#
ObjectQuery<Customer> query =
New ObjectQuery<DbDataRecord>(sqlText, context);
Visual Basic
Dim query As New ObjectQuery(Of DbDataRecord)(sqlText, context)
Retrieving Entity Data Through an ObjectQuery: C#
1 Open the “Chapter 15 CSharp” project from the installed samples folder The project
includes a Windows.Forms class named EntityQuery, which is a tool for trying out EF
queries
2 Open the source code view for the EntityQuery 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
Trang 33 Locate the ActSingleEntity_Click event handler This routine creates an ObjectQuery to
retrieve Customer entities Just after the “Retrieve the customer entities via a query” comment, within the try block, add the following statements:
ActiveContext = new SalesOrderEntities(GetConnectionString());
sqlText = @"SELECT VALUE Customer FROM Customers
AS Customer ORDER BY Customer.FullName DESC";
query = new ObjectQuery<Customer>(sqlText, ActiveContext);
This code creates a context (ActiveContext) and then creates an ObjectQuery pseudo-collection for Customer entities To guard against errors related to lazy loading of data,
the context remains open after this code completes
4 Run the program Click the Single Entity button to view the results of this example’s query.
Retrieving Entity Data Through an ObjectQuery: Visual Basic
1 Open the “Chapter 15 VB” project from the installed samples folder The project
in-cludes a Windows.Forms class named EntityQuery, which is a tool for trying out EF
queries
2 Open the source code view for the EntityQuery 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:
Trang 4sqlPortion.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 ActSingleEntity_Click event handler This routine creates an ObjectQuery to
retrieve Customer entities Just after the “Retrieve the customer entities via a query” comment, within the Try block, add the following statements:
ActiveContext = New SalesOrderEntities(GetConnectionString())
sqlText = "SELECT VALUE Customer FROM Customers " &
"AS Customer ORDER BY Customer.FullName DESC"
query = New ObjectQuery(Of Customer)(sqlText, ActiveContext)
This code creates a context (ActiveContext) and then creates an ObjectQuery pseudo-collection for Customer entities To guard against errors related to lazy loading of data,
the context remains open after this code completes
4 Run the program Click the Single Entity button to view the results of this example’s query.
Trang 5
Running Queries Using a Provider
In standard ADO.NET data processing, SQL-based queries make their way to the target data through command and connection objects, and then ultimately through a provider such as the SQL Server ADO.NET provider
The Entity Framework hosts its own data provider: the EntityClient provider This provider
exposes much of the same connection and command functionality available with the
SQL Server and other native providers, but with the ability to query against entities in an
Entity Data Model The key classes for the EntityClient provider appear in the System.Data EntityClient namespace.
Using the EntityClient provider to query data covers the same general steps as are performed with other providers:
1 Create and open a connection using the EntityConnection class and a connection string.
2 Create an EntityCommand instance and then add the connection and the Entity SQL
statement to it
3 If the query contains @-prefixed parameters, add parameters objects as needed.
4 Call one of the command object’s Execute methods to process the query and return
data results
The command object includes the ExecuteNonQuery method for running queries with no return results; the ExecuteScalar method, which returns a single result; and ExecuteReader, which returns a single-pass data reader, EntityDataReader What is missing is the data adapter with its capability to move incoming data into a DataTable or DataSet instance Considering
all the other data-manipulation tools included with the Entity Framework, this is a small omission But if you need to push entity data into a standard ADO.NET structure, you will have to do so manually
When using the EntityCommand.ExecuteReader method to generate a data reader, you must pass CommandBehavior.SequentialAccess as a behavior argument.
C#
results = query.ExecuteReader(CommandBehavior.SequentialAccess);
Visual Basic
results = query.ExecuteReader(CommandBehavior.SequentialAccess)
Trang 6This option is normally used when retrieving binary large objects (BLOBs) and other large content blocks from the database, but its use is required with the EntityClient provider, even when returning minimal content The side effect of using the sequential access option is that each returned row’s data values must be retrieved in the same order in which they appear
in the SQL statement and can be accessed only once each After you read a field, it’s time to move on to the next one
The following exercise shows the EntityClient provider in action, using a parameterized query
and a data reader to shuttle results into a DataTable instance.
Retrieving Entity Data Through a Provider: C#
Note This exercise continues the previous exercise in this chapter.
1 Locate the ActDataTable_Click event handler; this is a routine that copies entity-based
data into a standard ADO.NET DataTable instance Because the data will be shuttled
manually into an existing data table, the routine includes code to build the receiving table
resultsAsTable = new DataTable;
resultsAsTable.Columns.Add("CustomerID", typeof(long));
resultsAsTable.Columns.Add("CustomerName", typeof(string));
resultsAsTable.Columns.Add("AnnualFee", typeof(decimal));
Most of the routine is contained within a using block that manages the provider
connection
using (EntityConnection linkToDB =
new EntityConnection(GetConnectionString()))
{
// - Most of the code appears here
}
2 Just after the “Retrieve the data via a parameterized query” comment, add the
follow-ing statement:
sqlText = @"SELECT CU.ID, CU.FullName, CU.AnnualFee
FROM SalesOrderEntities.Customers AS CU
WHERE CU.AnnualFee >= @MinFee ORDER BY CU.FullName";
The EntityClient provider supports parameterized queries, as shown in these lines
3 In the same section of code, within the try block that follows the newly added SQL
statement, add these lines:
query = new EntityCommand(sqlText, linkToDB);
query.Parameters.AddWithValue("MinFee", 200);
results = query.ExecuteReader(CommandBehavior.SequentialAccess);
As mentioned previously, the CommandBehavior.SequentialAccess option is required.
Trang 74 Just after the “Move each row into the DataTable” comment, within one of the later try
blocks, add the following code:
while (results.Read())
{
oneRow = resultsAsTable.NewRow();
oneRow["CustomerID"] = (long)results["ID"];
oneRow["CustomerName"] = (string)results["FullName"];
oneRow["AnnualFee"] = (decimal)results["AnnualFee"];
resultsAsTable.Rows.Add(oneRow);
}
These lines move the data from the reader into the preconfigured DataTable instance
As is required by the sequential access flag used when creating the reader, the incom-ing fields are accessed in the order in which they appeared in the SQL query, and each field is accessed only once
5 Run the program Click the Data Table button to view the results of this example’s
query
Trang 8Retrieving Entity Data Through a Provider: Visual Basic
Note This exercise continues the previous exercise in this chapter.
1 Locate the ActDataTable_Click event handler; this is a routine that copies entity-based
data into a standard ADO.NET DataTable instance Because the data will be shuttled
manually into an existing data table, the routine includes code to build the receiving table
resultsAsTable = New DataTable
resultsAsTable.Columns.Add("CustomerID", GetType(Long))
resultsAsTable.Columns.Add("CustomerName", GetType(String))
resultsAsTable.Columns.Add("AnnualFee", GetType(Decimal))
Most of the routine is contained within a Using block that manages the provider
connection
Using linkToDB As New EntityConnection(GetConnectionString())
' - Most of the code appears here
End Using
2 Just after the “Retrieve the data via a parameterized query” comment, add the
follow-ing statement:
sqlText = "SELECT CU.ID, CU.FullName, CU.AnnualFee " &
"FROM SalesOrderEntities.Customers AS CU " &
"WHERE CU.AnnualFee >= @MinFee ORDER BY CU.FullName"
The EntityClient provider supports parameterized queries, as shown in these lines
3 In the same section of code, within the Try block that follows the newly added SQL
statement, add these lines:
query = New EntityCommand(sqlText, linkToDB)
query.Parameters.AddWithValue("MinFee", 200)
results = query.ExecuteReader(CommandBehavior.SequentialAccess)
As mentioned previously, the CommandBehavior.SequentialAccess option is required.
4 Just after the “Move each row into the DataTable” comment, within one of the later Try
blocks, add the following code:
Do While (results.Read() = True)
oneRow = resultsAsTable.NewRow()
oneRow!CustomerID = CLng(results!ID)
oneRow!CustomerName = CStr(results!FullName)
oneRow!AnnualFee = CDec(results!AnnualFee)
resultsAsTable.Rows.Add(oneRow)
Loop
Trang 9These lines move the data from the reader into the preconfigured DataTable instance
As is required by the sequential access flag used when creating the reader, the incom-ing fields are accessed in the order in which they appeared in the SQL query, and each field is accessed only once
5 Run the program Click the Data Table button to view the results of this example’s
query
Summary
This chapter reviewed the Entity SQL language and its usage within NET applications Entity SQL is built with the same basic query language syntax found in SQL Server’s Transact-SQL and in other variations of SQL Although there are some differences when dealing with the object nature of the Entity Framework, teams already working with SQL will have little trou-ble integrating Entity SQL into their applications
Although Entity SQL is great for organizations that have a large investment in SQL technolo-gies, it might not be the most straightforward EF-query tool for your needs The upcoming chapters introduce additional ways that Entity Framework data can be accessed within your software and your business logic
Trang 10Select entity records using Entity SQL Write your query using the Entity SQL language.
Create an instance of the entity context.
Create an instance of ObjectQuery<class>, where class is
an entity type, EF custom type, or DbDataRecord.
Access the members of the ObjectQuery instance.
Select the ID of all Product entity instances Use a query similar to the following:
SELECT p.ID FROM Products AS p
If the collection of entities was designed with a plural name, use that plural name in the query.
Select a single value as a data-type value instead
of as a row containing that value
Use the SELECT VALUE syntax.