Professional ASP.NET 1.1 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Professional ASP.NET 1.1 [Electronic resources] - نسخه متنی

Alex Homeret

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








Updating Data Sources with Transactions


One of the features of most database systems, and some other types of data store, is the ability to use transactions. Simply put, a transaction is a series of events that are all completed, or of which none are completed–there is never an intermediate result where some but not all of the events within the transaction occur.


The name transaction comes from real-world scenarios such as purchasing an item in a store where you give the seller money in exchange for goods. Unless one of you gets cheated, the transaction will either succeed with both parties happy at the outcome (you pay your money and get your goods), or fail where neither action occurs. There should never be an outcome where you pay money and don''t get the goods, or where you get goods but don''t pay the money.


In this section, you''ll look at two types of transactions:





Database transactions, where database-specific statements control the transaction and it is carried out within the database itself. Usually the stored procedure within the database contains the transaction statements.





Connection-based transactions, where the statements that control the transaction, and the execution and management of that transaction are outside the database. Usually these are a feature of the


Connection object that executes a SQL statement or stored procedure.






Note


While it is possible to write stored procedures that perform transactions across different databases on the same server, this is outside the scope of this chapter. It is also possible to use the services of another application, such as Windows 2000 Component Services (or MTS in Windows NT4) to perform a distributed transaction, where a series of events spread across different databases and applications on different servers are managed as a single transaction. Chapter 17 looks briefly at this topic.







Database Transactions



In a database system such as SQL Server, you can specify transaction operations within a stored procedure using vendor-specific statements like


BEGIN TRANSACTION to start a new transaction,


COMMIT TRANSACTION to accept all the updates and permanently commit the changes to the data, and


ROLLBACK TRANSACTION to cancel all the changes made within the current transaction.


We''ve provided an example page that uses a transacted stored procedure. The stored procedure, named


DoBookArchive , is created within the


WroxBooks database by the SQL script provided with the samples.


The DoBookArchive Stored Procedure



The


DoBookArchive stored procedure moves a row from the


BookList table into another table named


ArchiveBooks , within the same database. If the process succeeds, the transaction is committed and the updates are permanently applied to the database tables. If there is an error when writing to the


ArchiveBooks table, or when deleting the book from the


BookList table, both actions are rolled back and the tables are left in exactly the same state as before–neither is affected by the procedure.


However, to make it repeatable while you are experimenting with the example, the stored procedure always starts by deleting any existing book with the same ISBN (the primary key) in the


ArchiveBooks table. This action will also be rolled back if the complete transaction fails, so if a book has been archived (and hence deleted from the


BookList table) it will not be deleted from the


ArchiveBooks table if you run the stored procedure again with the same ISBN. In this case, the


INSERT statement will fail because the book is not in the


BookList table, and so the entire transaction is rolled back undoing the


DELETE operation on the


ArchiveBooks table. The code for the stored procedure follows:




CREATE PROCEDURE DoBookArchive


@ISBN varchar(12), @Result integer output AS


DECLARE @verror int


BEGIN TRANSACTION


DELETE FROM ArchiveBooks WHERE ISBN=@ISBN


INSERT INTO ArchiveBooks (ISBN, Title, PublicationDate)


SELECT * FROM BookList WHERE ISBN LIKE @ISBN


SELECT @verror = @@ERROR, @Result = @@ROWCOUNT


IF @verror <> 0 GOTO on_error


IF @Result > 0


BEGIN


DELETE FROM BookList WHERE ISBN=@ISBN


IF @@ERROR <> 0 GOTO on_error


COMMIT TRANSACTION


END


ELSE


ROLLBACK TRANSACTION


RETURN


on_error:


SELECT @Result = -1


ROLLBACK TRANSACTION


RETURN



The Transacted Stored Procedure Example



The example page Updating Data with a Transacted Stored Procedure (


transacted-storedproc.aspx ) uses the stored procedure just described. We''ve arranged for it to use the same ISBN code as the previous example that inserts and deletes a book in the


BookList table, so that you can see the results of this example by running it after inserting the new book and after deleting it. As shown in Figure 10-5, the stored procedure in this example will succeed providing that you have run the previous example to insert the new book row:





Figure 10-5:


If you then run the page again, as in Figure 10-6, it will show that the stored procedure failed to find the book in the


BookList table (because, of course, it''s just been moved to the


ArchiveBooks table):





Figure 10-6:


The Code for the Transacted Stored Procedure Example



As in the earlier examples, let''s start by specifying the name of the stored procedure and displaying it in the page, and then create the


Connection and


Command objects you''ll need to execute it. Also set the


CommandType of the


Command object to indicate that you''ll be executing a stored procedure. Then you can create the parameters for the command. This time there are only two–an input parameter to hold the ISBN of the book you want to archive and an output parameter to hold the result.




''specify the stored procedure name


Dim strSQL As String = "DoBookArchive"


outSQL.InnerText = strSQL ''and display it




''create connection and command


Dim objConnect As New OleDbConnection(strConnect)


Dim objCommand As New OleDbCommand(strSQL, objConnect)


objCommand.CommandType = CommandType.StoredProcedure




''create an input Parameter object named ''ISBN'' with the correct data


''type to match a SQL database ''varchar'' field of 12 characters


Dim objParam As OleDbParameter


objParam = objCommand.Parameters.Add("ISBN", OleDbType.VarChar, 12)


objParam.Direction = ParameterDirection.Input


objParam.Value = "199999999"




''create an output Parameter object named ''Result'' with the correct


''data type to match a SQL database ''integer'' field


''specify that it''s an Output parameter so no value required


objParam = objCommand.Parameters.Add("Result", OleDbType.Integer)


objParam.Direction = ParameterDirection.Output




''display the value of the input parameter


outInParams.InnerText = "ISBN=''" & objCommand.Parameters("ISBN").Value & "''"



Executing the Stored Procedure and Displaying the Results



The next step is to open your connection and execute the stored procedure. Then you can collect the result from the output parameter and display it, along with some accompanying explanatory text.




Try


''execute the stored procedure


objConnect.Open()


objCommand.ExecuteNonQuery()


objConnect.Close()


Catch objError As Exception


outError.InnerHtml = "* Error while updating original data.<br />" _


& objError.Message & "<br />" & objError.Source


Exit Sub ''stop execution


End Try


''collect and display the value of the output parameter


Dim intResult As Integer = objCommand.Parameters("Result").Value


Dim strResult As String = "Result=''" & CStr(intResult) & "''<br />"


Select Case intResult


Case -1: strResult &= "Error occurred while attempting archive"


Case 0: strResult &= "Failed to archive book – no matching book found"


Case > 0: strResult &= "Successfully archived the specified book"


End Select


outOutParams.InnerHtml = strResult



Notice that you didn''t have to do anything extra to benefit from the transaction within the stored procedure–you just executed it and checked the result to see what actually happened. This is not the case, however, when you use the other type of transaction, a connection-based transaction. You''ll see how different working with this type of transaction is next.



Connection-Based Transactions



The previous example shows how you can use a transaction within a stored procedure (a database transaction) to ensure that operations on your data either all succeed or are all rolled back. A second way of using a transaction is through the capabilities of the


Connection object. All


Connection objects (


SqlConnection, OelDbConnection ,


OdbcConnection , and


OracleConnection) can be used to perform transacted data updates.


While the way you actually apply a transaction is different from the stored-procedure transaction used in the previous example, the terminology is broadly the same. The three methods of the


Connection class concerned with managing transactions are shown in the following table.
















Connection.BeginTransaction




Starts a new transaction on this connection and all subsequent changes to the data become part of the transaction until it is committed or rolled back.




Transaction.Commit




Commits all changes made to the data within this transaction since it was started. The changes are made permanent in the target data store.




Transaction.Rollback




Abandons all changes made to the data within this transaction since it was started. The changes are removed from the target data store.




The Transaction Class



In ADO.NET, there are separate classes that implement transactions, one for each of the different types of


Connection . To start a transaction, call the


BeginTransaction method of the current


Connection object. This returns a


Transaction object that you must then assign to any


Command objects that you want to enroll into that transaction.


To end a transaction and commit all the changes to the database, call the


Commit method of the


Transaction object (note that it''s not a method of the


Connection object as you might at first have expected). To abandon all changes to the data, you can call the


Transaction object''s


Rollback method instead.


Notice also that you have to manually enroll any


Command objects into the transaction. While this might seem odd, it does allow you to have multiple transactions in progress, and use whichever is appropriate for each command you carry out on the database. You can also create a nested transaction (that is a transaction that executes within another transaction) by creating a new


Transaction object and calling the


Begin method.


A Connection-Based Transaction Example



To see the transaction methods in action, open the example Transactional Data Updates with a Command Object (


update -


with -


transaction.aspx ) shown in Figure 10-7. This page creates three SQL statements that are used to update the titles of three books in the


BookList table to reflect the current date and time, and then it executes these statements. Afterwards, it reads the rows back from the database and displays the details to confirm that the updates were successful.





Figure 10-7:


You can see in Figure 10-7 that the transaction was committed, and the three rows were updated. However, this is only because the page contains logic that uses the current time in seconds to decide whether to commit or roll back the transaction. While not a real-world scenario, it is done so that you can see the result of rolling back a transaction as well as committing it. After running the page again where the time has an even number of seconds, as shown in Figure 10-8, the transaction is rolled back and so the titles are not updated.





Figure 10-8:


The Code for the Connection-Based Transaction Example



The only real differences in the way that this page works, when compared to the other examples that use SQL statements to update the data source, is that you have to call the transaction methods at the appropriate times–effectively managing the transaction yourself. Instead of a stored procedure within the database itself deciding whether to commit or rollback the changes (usually dependent on the outcome of one of the statements in the stored procedure), you decide within your ASP code if the transaction should be committed or rolled back.


As usual, start by creating the SQL statements you''ll be executing against the


BookList table to update the book titles, as shown in the following code. Then you can create your


Connection and


Command objects, and declare a variable to hold the number of rows affected by your updates. The initial value is set to zero here, though this is not actually required (zero is the default value), but it helps to illustrate how the code works, and ensures that you can safely add on the result each time you execute a SQL statement.




''specify the SQL statements to update the data


Dim strNow, strSQL1, strSQL2, strSQL3 As String


Dim datNow As DateTime = Now()


strNow = datNow.ToString("dd-M-yy \a\t hh:mm:ss")


strSQL1 = "UPDATE BookList SET Title = ''Book One Written on " _


& strNow & "'' WHERE ISBN=''1100000001''"


outSQL1.InnerText = strSQL1 ''and display it


strSQL2 = "UPDATE BookList SET Title = ''Book Two Written on " _


& strNow & "'' WHERE ISBN=''1100000002''"


outSQL2.InnerText = strSQL2 ''and display it


strSQL3 = "UPDATE BookList SET Title = ''Book Three Written on " _


& strNow & "'' WHERE ISBN=''1100000003''"


outSQL3.InnerText = strSQL3 ''and display it




''create connection and command and variable to hold result


Dim objConnect As New OleDbConnection(strConnect)


Dim objCommand As New OleDbCommand()


Dim intRowsAffected As Integer = 0



Starting a Transaction


You need a variable to hold the


Transaction object that will be returned when we start a transaction, and so declare this next, as shown in the following code. Then open your connection, and execute the


BeginTransaction method to start a new connection-based transaction. You can assign the


Transaction object that is returned to your


objTransaction variable.


Now you are ready to execute your three SQL


UPDATE statements using the


Command object you created earlier on. You created it without providing any values for the constructor parameters, so you have to assign your


Connection object to its


Connection property. Also set the


CommandType to indicate that you''re using a SQL statement (though this is the default if not specified). Once your


Command object is set up, you also have to enroll it into the current transaction.


Notice that you can only do so after you''ve set the


Connection property, and if you want to change the


Connection property afterwards you first have to un-enrol it by setting the


Transaction property of the


Command object to


Nothing .




''declare a variable to hold a Transaction object


Dim objTransaction As OleDbTransaction




Try




''open connection before starting transaction


objConnect.Open()




''start a transaction for this connection


objTransaction = objConnect.BeginTransaction()




''specify the Connection object and command type for the Command


objCommand.Connection = objConnect


objCommand.CommandType = CommandType.Text




''attach the current transaction to the Command object


''must be done after setting Connection property


objCommand.Transaction = objTransaction



Executing the Commands and Committing or Rolling Back


The next step is to assign each SQL statement to the


CommandText property in turn and execute it. Then the next place where you need to consider how to handle the transaction that you''ve started is if an error occurs while executing the SQL statements. In an error situation, you would usually call the


Rollback method of the


Transaction object to cancel any changes that have been applied to the source data as shown.


If there is no error, and all three SQL statements have successfully executed, you would normally call the


Commit method of the


Transaction object to permanently apply the changes to the data store. However, in this example, check the number of seconds in the current time and only call


Commit if this is an odd number. If it''s an even number, you can call the


Rollback method to abandon all updates.




''specify the select statement to use for the first update


objCommand.CommandText = strSQL1




''execute the SQL statement against the command to fill the DataReader


''keep track of number of records originally updated


intRowsAffected += objCommand.ExecuteNonQuery()




''repeat using the select statement for the second update


objCommand.CommandText = strSQL2


intRowsAffected += objCommand.ExecuteNonQuery()




''repeat using the select statement for the third update


objCommand.CommandText = strSQL3


intRowsAffected += objCommand.ExecuteNonQuery()




Catch objError As Exception




''error encountered so roll back all the updates


objTransaction.Rollback()


''display error details


outError.InnerHtml = "* Error while updating original data.<br />" _


& objError.Message & "<br />" & objError.Source


Exit Sub '' and stop execution




End Try




''all seems OK so can now commit all the updates. However as an


''illustration of the technique only do so if the current time


''has an odd number of seconds. If not, rollback all changes


Dim strCommit As String


If Second(datNow) Mod 2 = 0


objTransaction.Rollback()


strCommit = "rolled back"


Else


objTransaction.Commit()


strCommit = "committed"


End If



Afterwards you can read the values of the rows using a


DataReader object and display them in the page. This is identical to the way you did it in the first example in this chapter, so the code is not repeated here.


Having looked briefly at how you can use transactions to ensure multiple data updates all succeed, or all fail, we''ll move on to a different topic. The


DataSet object introduced in previous chapters has the facility to automatically update the source data from which it was created–or in fact any data store for which the structure and contents of the tables within the


DataSet are of the appropriate format. This is the focus of the next section.


/ 244