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

Querying Databases

18 238 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

Nội dung

Chapter 9 Querying Databases After completing this chapter, you will be able to:  Issue data-modifying queries on external data sources  Retrieve a table of records from a SQL Server database  Return the primary key value for a newly inserted database record Despite its capability to work with data generated completely within an application, ADO.NET’s main purpose is to access and manipulate data in external data stores. To enable this query- and-update functionality on the source data platform, ADO.NET includes a “command” ob- ject, a wrapper around a platform-specific query that updates, inserts, or deletes target data; or returns single or multiple values from the data source. This chapter introduces this command wrapper, and demonstrates how to process records returned from a data query. ADO.NET does not impose any limits on the content of the que- ry statements because they are simply passed on to the data platform. However, the results that come back might require special handling depending on the structure of the returned data. Note This chapter focuses on the SQL Server provider and its implementation of command- related processing features. The OLE DB and ODBC providers include conceptually identical features, although some of the class names and processing details might differ. For complete information on these providers, refer to the Visual Studio online help. Processing SQL Queries SQL is the lingua franca of relational database processing. Although most database systems include specialized tools that let you organize data values and the table constructs that con- tain them, you can manage most essential features by crafting queries in SQL. From table creation to multitable data queries, SQL includes data definition and manipulation com- mands that give those with sufficient security rights complete control over the database and its content. Dwonloaded from: iDATA.ws 136 In SQL Server databases, the SQL language includes different types of statements, including the following:  SQL query statements Selection queries that return data results  Data manipulation statements Statements that modify or change data content  Data definition statements Commands that modify tables and other structures that support the data content  Stored procedures Named blocks of processing logic ADO.NET lets you process any of these statement types through instances of the System. Data.SqlClient.SqlCommand class. This class encapsulates one or more SQL statements and includes methods that request processing of the statement(s) on a SQL Server connection, optionally returning query results. Note In the OLE DB provider, the equivalent command class is located at System.Data. OleDb.OleDbCommand, whereas the ODBC provider version is found at System.Data.Odbc. OdbcCommand. These two classes and the SqlCommand class in the SQL Server provider all derive from System.Data.Common.DbCommand. Creating Command Objects Using the SqlCommand class is a straightforward procedure: 1. Create an instance of SqlCommand. 2. Assign a valid SQL statement to the object’s CommandText property. 3. Set the object’s Connection property to an open SqlConnection instance. 4. Assign other optional properties as needed. 5. Call one of the object’s many synchronous or asynchronous “execute” methods. The SqlCommand object’s constructor has various overloaded versions that let you specify the SQL statement text and the ADO.NET connection as arguments. Dwonloaded from: iDATA.ws Chapter 9 Querying Databases 137 C# SqlConnection linkToDB = new SqlConnection(connectionString); linkToDB.Open(); string sqlText = @"UPDATE WorkTable SET ProcessedOn = GETDATE() WHERE ProcessedOn IS NULL"; SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); Visual Basic Dim linkToDB As New SqlConnection(connectionString) linkToDB.Open() Dim sqlText As String = "UPDATE WorkTable SET ProcessedOn = GETDATE() " & "WHERE ProcessedOn IS NULL" Dim dataAction As New SqlCommand(sqlText, linkToDB) The SqlCommand.CommandText field accepts two types of string data:  Standard SQL statements This is the default type. Normally, only a single SQL state- ment appears in this field. However, you can include multiple semicolon-delimited statements within a single command instance. Information on retrieving the results of multiple SELECT statements from a single command appears later in this chapter.  Stored procedures The command text field contains the stored procedure name. Set the SqlCommand.CommandType property to CommandType.StoredProcedure. You add any “in” or “out” arguments to the command through distinct parameters. See Chapter 10, “Adding Parameters to Queries,” for details on using parameters. If you want to in- clude the arguments within the command text itself (as is commonly done through SQL Server’s Management Studio tool), treat the text as a standard SQL statement, setting the CommandType property to CommandType.Text. Note The SqlCommand.CommandType property also accepts a value of CommandType. TableDirect, which indicates that the CommandText field contains nothing more than a table name to be used for row retrieval and management. The SQL Server provider does not support this command variation. Processing Queries The command object works for queries that return data values from the data source, and also for statements that take some action on the database but that return no stored data. These “nonquery” actions are typical when adding, updating, or removing records from the database; or when processing Data Definition Language commands, such as SQL Server’s CREATE TABLE statement. Dwonloaded from: iDATA.ws 138 Microsoft ADO.NET 4 Step by Step To run a nonquery, create a new SqlCommand object and set its command text to the server- side SQL statement. Then call the object’s ExecuteNonQuery method. C# string sqlText = "DELETE FROM WorkTable WHERE Obsolete = 1"; SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); try { dataAction.ExecuteNonQuery(); } catch (Exception ex) { MessageBox.Show("Failure: " + ex.Message); } Visual Basic Dim sqlText As String = "DELETE FROM WorkTable WHERE Obsolete = 1" Dim dataAction As New SqlCommand(sqlText, linkToDB) Try dataAction.ExecuteNonQuery() Catch ex As Exception MessageBox.Show("Failure: " & ex.Message) End Try ExecuteNonQuery sends the command text to the data source through the previously opened connection. Any processing errors, including those generated by the data source, throw an exception. Calls to stored procedures work the same way. C# string sqlText = "dbo.CancelOrder " + orderID; SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); dataAction.ExecuteNonQuery(); Visual Basic Dim sqlText As String = "dbo.CancelOrder " & orderID Dim dataAction As New SqlCommand(sqlText, linkToDB) dataAction.ExecuteNonQuery() Dwonloaded from: iDATA.ws Chapter 9 Querying Databases 139 Note Building SQL statements through string concatenation, especially with user-supplied com- ponents, can be risky. Chapter 10, “Adding Standards to Queries,” introduces command param- eters, which can reduce or eliminate these risks. Parameters also let your code retrieve data from stored procedure “out” parameters. Processing Asynchronously The ExecuteNonQuery method is synchronous; your application will block until the database operation completes successfully or aborts with an error or connection timeout. If your ap- plication is single threaded, it will cease to function (or at least appear that way) until the method returns. The command object also supports asynchronous processing of nonqueries. It includes a pair of methods—BeginExecuteNonQuery and EndExecuteNonQuery—that bracket the operation. The BeginExecuteNonQuery method returns an object with the interface System.IAsyncResult that sets its IsCompleted property to True when processing ends. At that point, your code must call the EndExecuteNonQuery method to complete the process. C# SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); IAsyncResult pending = dataAction.BeginExecuteNonQuery(); while (pending.IsCompleted == false) { // ----- Do work as needed, or . Threading.Thread.Sleep(100); } dataAction.EndExecuteNonQuery(pending); Visual Basic Dim dataAction As New SqlCommand(sqlText, linkToDB); Dim pending As IAsyncResult = dataAction.BeginExecuteNonQuery() Do While (pending.IsCompleted = False) ' ----- Do work as needed, or . Threading.Thread.Sleep(100) Loop dataAction.EndExecuteNonQuery(pending) A variation of the BeginExecuteNonQuery method lets you specify a callback method and an optional object that will be passed to the callback method when the operation completes. You must still call EndExecuteNonQuery, although you can call it from within the callback code. Passing the SqlCommand object as the optional argument simplifies this process. Dwonloaded from: iDATA.ws 140 Microsoft ADO.NET 4 Step by Step C# SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); AsyncCallback callback = new AsyncCallback(WhenFinished); dataAction.BeginExecuteNonQuery(callback, dataAction); // ----- Elsewhere . private void WhenFinished(IAsyncResult e) { // ----- The IAsyncResult.AsyncState property contains the // optional object sent in by BeginExecuteNonQuery. SqlCommand dataAction = (SqlCommand)e.AsyncState; // ----- Finish processing. dataAction.EndExecuteNonQuery(e); } Visual Basic Dim dataAction As New SqlCommand(sqlText, linkToDB) Dim callback As New AsyncCallback(AddressOf WhenFinished) dataAction.BeginExecuteNonQuery(callback, dataAction) ' ----- Elsewhere . Private Sub WhenFinished(ByVal e As IAsyncResult) ' ----- The IAsyncResult.AsyncState property contains the ' optional object sent in by BeginExecuteNonQuery. Dim dataAction As SqlCommand = CType(e.AsyncState, SqlCommand) ' ----- Finish processing. dataAction.EndExecuteNonQuery(e) End Sub The connection used by the command must remain open during processing. If you want to halt execution of the command before it completes, call the SqlCommand object’s Cancel method. Be aware that—depending on the state of processing—the Cancel method might or might not cancel the execution in time. Returning Query Results Sending commands to a database is useful; getting data back is also essential for data-centric applications. The command object includes several methods that return both single values and multiple rows of tabular data. Dwonloaded from: iDATA.ws Chapter 9 Querying Databases 141 Returning a Single Value The SqlCommand object’s ExecuteScalar method sends a SQL command or stored procedure request to the database, just like the ExecuteNonQuery method, but it also returns a single value produced by the query. This method is useful with SELECT queries that return a simple result. C# string sqlText = "SELECT COUNT(*) FROM WorkTable"; SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); int totalItems = (int)dataAction.ExecuteScalar(); Visual Basic Dim sqlText As String = "SELECT COUNT(*) FROM WorkTable" Dim dataAction As New SqlCommand(sqlText, linkToDB) Dim totalItems As Integer = CInt(dataAction.ExecuteScalar()) Because ExecuteScalar returns data of type System.Object, you must coerce it into the ex- pected data type. The method can return System.DBNull for nondata results. SQL Server 2005 introduced a new OUTPUT keyword on INSERT statements that returns a specified field (typically the primary key) from the newly inserted data row. Before this change, programmers often had to issue two statements to obtain this new key value: the first to insert the record and the second to retrieve the primary key through a new SELECT statement. By combining the OUTPUT keyword with the ExecuteScalar method, it’s easy to obtain the primary key in a single command. C# // ----- Pretend the .'s represent actual fields, and that // WorkTable.ID is the name of the primary key. string sqlText = @"INSERT INTO WorkTable ( .) OUTPUT INSERTED.ID VALUES ( .)"; SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); int newID = (int)dataAction.ExecuteScalar(); Visual Basic ' ----- Pretend the .'s represent actual fields, and that ' WorkTable.ID is the name of the primary key. Dim sqlText As String = "INSERT INTO WorkTable ( .) " & "OUTPUT INSERTED.ID VALUES ( .)" Dim dataAction As New SqlCommand(sqlText, linkToDB) Dim newID As Integer = CInt(dataAction.ExecuteScalar()) Stored procedures that return a single value are identical in concept. Dwonloaded from: iDATA.ws 142 Microsoft ADO.NET 4 Step by Step Returning Data Rows To process one or more rows returned from a SELECT query or row-producing stored pro- cedure, use the SqlCommand object’s ExecuteReader method. This method returns an object of type System.Data.SqlClient.SqlDataReader, which lets you scan through the returned rows once, examining the columnar data values in each row. The data reader is fast and light- weight, providing no-nonsense access to each row’s values. Note ExecuteReader accesses the database in a synchronous manner. SqlCommand also in- cludes a BeginExecuteReader and EndExecuteReader method pair that enables asynchronous access to the data. The discussion of asynchronous processing earlier in this chapter also applies to these methods. To create the reader, add the relevant command text and connection to a SqlCommand, and call its ExecuteReader method to return the new SqlDataReader instance. C# string sqlText = "SELECT ID, FullName, ZipCode FROM Customer"; SqlCommand dataAction = new SqlCommand(sqlText, linkToDB); SqlDataReader scanCustomer = dataAction.ExecuteReader(); Visual Basic Dim sqlText As String = "SELECT ID, FullName, ZipCode FROM Customer" Dim dataAction As New SqlCommand(sqlText, linkToDB) Dim scanCustomer As SqlDataReader = dataAction.ExecuteReader() SqlDataReader exposes exactly one data row at a time as a collection of column values. The reader returned by ExecuteReader doesn’t yet point to a data row. You must call the reader’s Read method to access the first row, calling it again for subsequent rows. Read returns False when there are no more rows available. The HasRows property indicates whether any rows were returned from the query. C# SqlDataReader scanCustomer = dataAction.ExecuteReader(); if (scanCustomer.HasRows) while (scanCustomer.Read()) { // ----- Perform row processing here. } scanCustomer.Close(); Dwonloaded from: iDATA.ws Chapter 9 Querying Databases 143 Visual Basic Dim scanCustomer As SqlDataReader = dataAction.ExecuteReader() If (scanCustomer.HasRows = True) Then Do While scanCustomer.Read() ' ----- Perform row processing here. Loop End If scanCustomer.Close() Always call the reader’s Close or Dispose method when finished. By default, SQL Server will permit only a single reader to be open at once. To open another reader, you must close the previous one. This also applies to other types of queries. Statements issued through the SqlCommand.ExecuteNonQuery method will also fail if a SqlDataReader is open and in use. Note If you include the MultipleActiveRecordSets=True key-value pair in the SQL Server connec- tion string used to access the database, you will be able to open multiple readers at once and process other commands while a reader is open. However, be careful when using this feature because you won’t get a warning if you inadvertently leave a reader open. When you close the data reader, the associated connection remains open for your further use, until you specifically close the connection. Passing CommandBehavior.CloseConnection as an argument to ExecuteReader tells the reader to close the connection when the reader closes. C# SqlDataReader scanCustomer = dataAction.ExecuteReader(CommandBehavior.CloseConnection); // ----- Scan through the reader, then . scanCustomer.Close(); // ----- The connection closes as well. Visual Basic Dim scanCustomer As SqlDataReader = dataAction.ExecuteReader(CommandBehavior.CloseConnection) ' ----- Scan through the reader, then . scanCustomer.Close() ' ----- The connection closes as well. SqlDataReader is a unidirectional, read-once construct. After you scan through all the avail- able rows using the Read method, that’s it. You cannot return to the beginning of the set Dwonloaded from: iDATA.ws 144 Microsoft ADO.NET 4 Step by Step and scan through again; to do that, you’d need to generate a new data reader from a new command object. The reader’s forward-only, read-once limitation helps keep it speedy and memory-friendly. Accessing Field Values Accessing each field in a SqlDataReader is similar to the process used with a DataRow instance. Both objects include a default Item collection that exposes column values by zero-based position or by name. (If two fields share a common name that differs only by case, the name lookup is case-sensitive.) C# result = scanCustomer[0]; // By position result = scanCustomer["ID"]; // By name Visual Basic result = scanCustomer(0) ' By position result = scanCustomer!ID ' By name The official documentation for the SqlDataReader class says that this method returns data in its “native format.” In essence, it returns a System.Object instance. You need to cast the data to the appropriate data type. NULL data fields contain DBNull.Value. The reader’s IsDBNull method indicates whether a column at a specific ordinal position contains DBNull. For strongly typed access to fields, the data reader exposes a seemingly endless number of data-returning methods with names that indicate the format of the resulting value. For ex- ample, the SqlDataReader.GetDecimal method returns a System.Decimal value from one of the row’s fields. These methods accept only an ordinal position; if you want to use them with a field name, you must convert the name to its position using the GetOrdinal method. C# rowID = scanCustomer.GetInt64(scanCustomer.GetOrdinal("ID")); Visual Basic rowID = scanCustomer.GetInt64(scanCustomer.GetOrdinal("ID")) Dwonloaded from: iDATA.ws [...]... Chapter 9  Querying Databases 145 Naturally, you must use the appropriate function for a specific column For example, using the GetInt32 method on a non-numeric text column will fail Table 9-1 lists these typed methods... builder.DataSource = @"(local)\SQLExpress"; builder.InitialCatalog = "StepSample"; builder.IntegratedSecurity = true; Adjust these statements as needed to provide access to your own test database Chapter 9  Querying Databases 147 3 Locate the ExecuteSQL method This routine processes a SQL statement (sqlText) on a connected database (linkToDB), expecting no returned results Within the try block, add the following... database (linkToDB), expecting no returned results Within the Try block, add the following code: Dim commandWrapper As New SqlCommand(sqlText, linkToDB) commandWrapper.ExecuteNonQuery() Chapter 9  Querying Databases 149 4 Locate the ExecuteSQLReturn method This routine processes a SQL statement (sqlText) on a connected database (linkToDB), collecting a single return value from the database and returning... the reader’s various Get methods or the default Item property to retrieve field values on each scanned row When finished with a SqlDataReader, always call its Close or Dispose method Chapter 9  Querying Databases 151 Chapter 9 Quick Reference To Do This Run a SQL query over an ADO.NET connection Create a SqlCommand instance Set its CommandText property to the SQL statement Set its Connection property . Chapter 9 Querying Databases After completing this chapter, you will be able to:  Issue. the ADO.NET connection as arguments. Dwonloaded from: iDATA.ws Chapter 9 Querying Databases 137 C# SqlConnection linkToDB = new SqlConnection(connectionString);

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

Xem thêm

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN