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

Microsoft SQL Server 2005 Developer’s Guide- P11 doc

20 432 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

Định dạng
Số trang 20
Dung lượng 279,04 KB

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

Nội dung

For instance, using the SqlTransaction object to issue a BeginTransaction statement will send a T-SQL BEGIN TRANSACTION command to SQL Server.. In the beginning of this subroutine, you c

Trang 1

functions would be considered part of the same logical transaction From the

database standpoint, to ensure database integrity, both the withdrawal and the deposit

would be grouped together as a single transaction If the withdrawal operation

succeeded, but the deposit failed, the entire transaction could be rolled back, which

would restore the database to the condition it had before the withdrawal operation

was attempted Using transactions is an essential part of most production-level

database applications

ADO.NET supports transactions using the Transaction classes In order to

incorporate transactions into your ADO.NET applications, you first need to create an

instance of the SqlTransaction object and then execute the BeginTransaction method

to mark the beginning of a transaction Under the covers this will cause the database

server to begin a transaction For instance, using the SqlTransaction object to issue a

BeginTransaction statement will send a T-SQL BEGIN TRANSACTION command

to SQL Server After the transaction has started, the database update operations are

performed and then the Commit method is used to actually write the updates to the

target database If an error occurs during the process, then the RollBack operation

is used to undo the changes The following SQLCommandTransaction subroutine

shows how to start a transaction and then either commit the results of the transaction

to the database or roll back the transaction in the event of an error:

Private Sub SQLCommandTransaction(cn As SqlConnection)

Dim cmd As New SqlCommand()

Dim trans As SqlTransaction

' Start a local transaction

trans = cn.BeginTransaction()

cmd.Connection = cn

cmd.Transaction = trans

Try

' Insert a row transaction

cmd.CommandText = _

"INSERT INTO Department VALUES(100, 'Transaction 100')"

cmd.ExecuteNonQuery()

' This next insert will result in an error

cmd.CommandText = _

"INSERT INTO Department VALUES(100, 'Transaction 101')"

cmd.ExecuteNonQuery()

trans.Commit()

Catch e As Exception

MsgBox(e.Message)

trans.Rollback()

End Try

Trang 2

In the beginning of this subroutine, you can see where the SqlConnection object is passed in and a new instance of the SqlCommand object is created, followed by the definition of a SqlTransaction object named trans Next, a local transaction is started

by using the cn SqlConnection object’s BeginTransaction method to create a new instance of a SqlTransaction object Note that the connection must be open before you execute the BeginTransaction method Next, the cmd SqlCommand Connection property is assigned with the cn SqlConnection and the Transaction property is assigned with the trans SqlTransaction object

Within the Try-Catch block, two commands are issued that are within the local transaction scope The first command is an INSERT statement that inserts two columns into the Department table that was created previously in this chapter The first insert statement adds the DepartmentID of 100 along with a DepartmentName value of “Transaction 100.” The SqlCommand ExecuteNonQuery method is then used to execute the SQL statement Next, the cmd object’s CommandText property

is set to another SQL INSERT statement However, this statement will cause

an error because it is attempting to insert a duplicate primary key value In this second case, the DepartmentID of 100 is attempted to be inserted along with the DepartmentName value of “Transaction 101.” This causes an error because the DepartmentID of 100 was just inserted by the previous INSERT statement When the ExecuteNonQuery method is executed, the duplicate primary key error will be issued and the code in the Catch portion of the Try-Catch block will be executed

Displaying the exception message in a message box is the first action that happens within the Catch block You can see an example of this message in Figure 6-3 After the message box is displayed, the trans SqlTransaction object’s RollBack method is used to roll back the attempted transaction Note that because both insert statements were within the same transaction scope, both insert operations will be rolled back The resulting department table will not contain either DepartmentName

“Transaction 100” or DepartmentName “Transaction 101.”

Figure 6-3 A duplicate primary key error prevents the Commit operation.

Trang 3

Using the SqlDependency Object

SQL Server 2005 and ADO.NET 2.0 now contain a signaling solution in the data

provider and the database called Query Notifications Query Notifications allows

your application to request a notification from SQL Server when the results of

a query change You can design applications that query the database only when there

is a change to information that the application has previously retrieved

Query Notifications are implemented through the SQL Server 2005 Query Engine,

the SQL Server Service Broker, a system stored procedure (sp_DispatcherProc),

the ADO.NET System.Data.Sql.SqlNotificationRequest class, the System.Data

SqlClient.SqlDependency class, and the ASP.NET System.Web.Caching.Cache class

The basic process is as follows:

notification When the SqlCommand is executed and the Notification property

is not null, a request of notification is appended to the command request

Query Notifications and then executes the command

originally returned rowset If the rowset is changed, a message is sent to the

Service Broker Service The message can either send a notification back to

the registered client, or wait on the Service Broker’s Queue for retrieval by an

advanced client’s custom processing routine

The following example demonstrates the System.Data.SqlClient.SqlDependency

object Note that the application creates a System.Data.SqlClient.SqlDependency

object and registers to receive notifications via the System.Data.SqlClient

SqlDependency.OnChange event handler

Imports System

Imports System.Data

Imports System.Data.SqlClient

Imports System.ComponentModel

Public Class Form1

Dim cn As New SqlConnection()

Dim cmd As New SqlCommand

Private Sub StartNotification_Click( & _

ByVal sender As System.Object, ByVal e As System.EventArgs) & _

Handles StartNotification.Click

Trang 4

cn.ConnectionString = "SERVER=" & txt_Server.Text & _ ";database=AdventureWorks" & _

";UID=" & txt_UserID.Text & ";PWD=" & txt_Password.Text cmd.CommandText = "SELECT Category, Description, " & _ "DiscountPct FROM Sales.SpecialOffer"

cmd.Connection = cn

StartNotify()

End Sub

Private Sub StartNotify()

' Command Notification property starts as nothing

cmd.Notification = Nothing

' a SqlDependency object is attached to the Command object Dim dep As New SqlDependency

dep.AddCommandDependency(cmd)

AddHandler dep.OnChange, New OnChangeEventHandler( & _ AddressOf MyOnChange)

Try

' Open the connection

cn.Open()

Dim rdr As SqlDataReader

' Create the reader

rdr = cmd.ExecuteReader()

' Read results and add to a listbox on displayed form list_Results.Items.Clear()

Do While rdr.Read()

list_Results.Items.Add(rdr("Category") & vbTab & _ rdr.Item("Description") & vbTab & _

rdr.Item("DiscountPct"))

Loop

rdr.Close()

cn.Close()

list_Results.Update()

Catch e As Exception

MsgBox(e.Message)

End Try

End Sub

Private Sub MyOnChange(ByVal sender As Object, & _

ByVal args As SqlNotificationEventArgs)

' Check for safe UI update.

Trang 5

' If InvokeRequired True, code executing on a worker thread.

If i.InvokeRequired Then

' Create a delegate to perform the thread switch.

Dim tempDelegate As New OnChangeEventHandler( & _

AddressOf MyOnChange)

Dim argues() As Object = {sender, args}

' Marshal the data from worker thread to UI thread.

i.BeginInvoke(tempDelegate, argues)

Return

End If

' Remove the handler.

Dim dep As SqlDependency = CType(sender, SqlDependency)

RemoveHandler dep.OnChange, AddressOf MyOnChange

StartNotify()

End Sub

End Class

In the beginning of the code listing, the Import statements are placed in the

declarations section of the project file and a Form1 class is started A SqlConnection

object named cn is created and a new SqlCommand object named cmd is created The

next statement is the StartNotification_Click subroutine, which refers to the click event

of a button on a sample windows form Inside the subroutine, the SqlConnection’s

ConnectionString property is set using three textboxes on the form that provide the

server name, userid, password The database of Adventureworks is also used, but in

this case is hardcoded The SqlCommand’s CommandText property is set to select the

Category, Description, and DiscountPct field from the Sales.SpecialOffer table in

the AdventureWorks database Next, the cmd object’s Connection property is set to

the previously created cn object A subroutine called StartNotify is then called The

StartNotify subroutine is shown next in the code listing The cmd object’s Notification

property is first set to Nothing, then the SqlDependency object is created and added

to the cmd object using the AddCommandDependency method This will set the

cmd object’s Notification property to the SqlDependency object, which will append

a notification request to the command request when the command is executed An

OnChangeEventHandler is then created to process any change notifications that are

sent back to the application In the Try/Catch block, you can see that the connection

is then opened, a SqlDataReader is created, and the ExecuteReader function is called

The ExecuteReader command will retrieve the records from the Sales.SpecialOffer

table, as the SQL SELECT statement requested The SqlDataReader then reads

through the retrieved data and outputs it to a listbox on the windows form The reader

and connection are then closed and the listbox is refreshed to show the data

Trang 6

The next subroutine, MyOnChange, is the event handler that will execute when any of the originally retrieved data is changed at the server Here we do a little fancy footwork to move the incoming data from the notification from the worker thread

it came in on to the UI thread, so it can be displayed on the windows form The BeginInvoke method of the ISynchronizeInvoke object is used to set the receive notification process to asynchronous, which allows switching of communication threads A temporary event handler is created to handle the marshaled data and the original handler is removed While a discussion on the ISynchronizeInvoke object is beyond the scope of this chapter, this subroutine gives you a brief sample of how to marshal data between threads The StartNotify subroutine is then called to reset the handler and process the newly changed data and display it to the user in the listbox

Using the SqlDataReader Object

The DataReader is a unique entity in the ADO.NET framework While the rest of the ADO.NET framework was explicitly designed to work in a disconnected model, the DataReader has been designed to work in a more traditional connected fashion

The DataReader essentially provides a fast forward–only stream of data that’s sent from the database server to the application Thanks to these attributes, this is also known as

a fire hose cursor Unlike the much more feature-laden DataSet, the DataReader is

a very lightweight, high-performance object Also unlike the DataSet, the DataReader

is one-way In other words, it doesn’t allow you to directly update the data that’s retrieved That doesn’t mean that the data retrieved by the DataReader can’t be

changed—it can, but the DataReader doesn’t have any built-in mechanisms that allow updating To update the data retrieved by the DataReader, you would need to execute either SQL statements or stored procedures, or else move the data into a DataSet The DataReader is also created a bit differently than the other ADO.NET objects While most of the other ADO.NET objects, such as the Connection and Command objects, can be instantiated using a constructor (for instance, when you use the New keyword),

to create a DataReader, you must call the ExecuteReader method of the Command object One important consideration to keep in mind with the DataReader is that while the DataReader is in use, it will monopolize the associated Connection object No other operations can be performed using the Connection (other than closing it) until the Close method of the DataReader is executed

Trang 7

Retrieving a Fast Forward–Only Result Set

Retrieving a fast read-only stream of results from a SQL Server database is the

SqlDataReader’s primary purpose Retrieving quick read-only subsets of data is

one of the most common operations for a SQL Server database application, and

the SqlDataReader is the best ADO.NET object for this task in that it provides the

best data read performance of any ADO.NET object and has minimal overhead

The SqlDataReader maintains a constant connection state to the database from the

time the query is started until the database has returned the result stream, which

means that the SqlConnection object can’t be used for anything else while the

SqlDataReader is active The following example illustrates the basic usage of the

SqDataReader In this example you’ll see how to retrieve a basic read-only result set

from the SQL Server AdventureWorks database and then process the individual data

elements that compose the result stream

Private Sub SQLReaderForward(cn As SqlConnection)

' Setup the command

Dim cmd As New SqlCommand _

("SELECT CustomerID, CustomerType FROM Sales.Customer " _

& "WHERE TerritoryID = 4", cn)

cmd.CommandType = CommandType.Text

Dim rdr As SqlDataReader

Try

' Create the reader

rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)

' Read the results and add them to a listbox on displayed form

lstResults.Items.Clear()

Do While rdr.Read()

lstResults.Items.Add(rdr("CustomerID") & vbTab & _

rdr.Item("CustomerType"))

Loop

rdr.Close()

Catch e As Exception

MsgBox(e.Message)

End Try

End Sub

In the beginning of the SQLReaderForward subroutine, a SqlConnection object

named cn is passed in and a new SqlCommand object named cmd is created The

constructor sets the Command Property to a SQL SELECT statement that retrieves

the value of the CustomerID and CustomerType columns from the Sales.Customer

Trang 8

Table in the AdventureWorks database for all rows where the TerritoryID column is equal to 4 Since this is a SQL command, the CommandType is set to CommandText and then a new SqlDataReader named rdr is declared

NOTE

At this point you can’t use the SqlDataReader because, although the SqlDataReader object is declared, it has not been instantiated The SqlDataReader is only instantiated after the SqlCommand object’s ExecuteReader method has been called.

Inside the Try block the cmd SqlCommand object’s ExecuteReader is used to instantiate the SqlDataReader At this point the SqlDataReader is opened and ready

to use You might notice that the ExecuteReader method uses CommandBehavior CloseConnection enumeration, which automatically closes the connection when the SqlDataReader is closed The CommandBehavior member provides the Command object a description of the results of the query and also influences the effects of the query on the database Table 6-6 describes the available CommandBehavior options

CloseConnection The associated Connection object is closed when the DataReader object is closed Default No options are set This is equivalent to calling ExecuteReader()

KeyInfo The query returns column and primary key information This flag causes the SQL

Server NET Data Provider to append a FOR BROWSE clause to the statement being executed

SchemaOnly The query only returns column metadata and does not return a result set SequentialAccess This flag is used to handle access to BLOB (Binary Large Objects) When this

option is used, the DataReaders loads data as a stream rather than loading the entire row The GetBytes or GetChars methods can then be used to read the data buffer that’s returned

SingleResult The query is restricted to returning a single result set

SingleRow The query is expected to return a single row Using the SingleRow flag with the

ExecuteReader method of the OleDbCommand object causes the object to perform single-row binding using the OLE DB IRow interface Otherwise, the OLE DB NET Provider will perform binding using the IRowset interface

Table 6-6 ExecuteReader CommandBehavior Enumeration

Trang 9

Next, a While loop is used to read the forward-only data stream returned by the

SqlDataReader Within the While loop the two different data elements in the data

stream are added to a list box named lstResults that is defined on the Windows form

for this project In this example, each column in the result set is accessed using

a string that identifies the column name In other words, rdr(“CustomerID”) is used

to access the CustomerID column and rdr(“CustomerType”) is used to access the

CustomerType column Alternatively, you could also access the column returned by

the DataReader in a couple of other ways First you could use each column’s ordinal

position rather than the column name In this case you could use rdr(0) and rdr(1)

Using ordinals may execute a tiny bit faster, but the price you pay in code readability

isn’t worth the minuscule performance difference Next, each of the columns in

the result set returned by the SqlDataReader could also have been accessed using

the rdr.GetInt32(0) and rdr.GetString(1) methods The main difference between

these options is the fact that when you reference the DataReader columns directly

using the named columns, you get back the native NET Data Provider data type

types Using the GetInt32, GetString, or other similar data access methods returns

the NET Framework data type, and an error will be thrown if the data doesn’t

match the data type expected by the method In addition, the GetString, GetInt32,

and other data access methods accept only ordinal values and can’t be used with

string identified You should note that in all of these cases each column must be

accessed in the order it appears in the result set You cannot access the columns out

of order This is because the DataReader provides one-way streams of results to the

client application After all of the results have been retrieved, the rdr.Read method

will return the value of False and the while loop will be terminated; then the rdr

Close method is used to close the SqlDataReader Since the CommandBehavior

CloseConnection flag was used earlier by the ExecuteReader method, the connection

to the SQL Server database will also be closed

NOTE

Explicitly closing all of the ADO.NET objects is especially important because unlike in ADO, the

objects aren’t destroyed when they go out of scope Instead, if left to their own devices they are

destroyed when the NET garbage collector decides to remove them However, explicitly closing the

DataReader is particularly important because the connection can’t be used for anything else until

the DataReader is closed.

The code in the Catch block will be executed if an error occurs while using the

SqlDataReader In this case, the exception message will be captured and displayed in

a message box

Trang 10

Reading Schema-Only Information

The previous examples illustrated how to retrieve the data and basic column

headings using the SqlDataReader However, the SqlDataReader can also retrieve more detailed table schema information The metadata returned can help you determine how to process the columns that are returned by the DataReader The column schema information returned includes the column name and its data type,

as well as other information such as whether the column can accept null values The following SQLReaderSchema subroutine illustrates using the SqlDataReader’s GetTableSchema method to return the schema information for a given query:

Private Sub SQLReaderSchema(cn As SqlConnection)

' Setup the command

Dim cmd As New SqlCommand("SELECT * FROM Sales.Customer", cn) cmd.CommandType = CommandType.Text

Dim rdr As SqlDataReader

Try

' Create the reader

rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly)

' bind the returned DataTable to the grid & close

grdResults.SetDataBinding(rdr.GetSchemaTable(), "")

rdr.Close()

Catch e As Exception

MsgBox(e.Message)

End Try

End Sub

Like the previous examples, the SQLReaderSchema subroutine begins by creating

a new SqlCommand object named cmd In this case, the SqlCommand object contains

a SQL SELECT statement that retrieves all of the columns from the Sales.Customer table You might note that since this example doesn’t actually retrieve any data, it’s okay to use an unqualified query like this However, if this were a production query, you would have to make sure to specify the exact columns and rows that your application needed Next the CommandText property is set to CommandType.Text and a SqlDataReader object named rdr is declared

Next a Try block is used to execute the SqlDataReader If an error occurs inside the Try block, the code in the Catch block will be executed and message box will

be displayed There are two important points to notice about this example First, the cmd SqlCommand object’s ExcuteReader method uses the CommandBehavior SchemaOnly enumeration to specify that only schema metadata should be returned

by the SqlDataReader and that no data will be returned to the calling application

Ngày đăng: 03/07/2014, 01:20

TỪ KHÓA LIÊN QUAN