Concurrent code in ADO

xiaoxiao2021-03-06  22

Concurrent code in ADO

Release Date: 12/23/2004

| Update Date: 12/23/2004

Rick Dobson

What happens if two users try to update the same line? Since the shared database has been introduced, similar problems have been plaguing developers. Now, ADO.NET solves this problem with a method called "open concurrency". Rick Dobson illustrates the working principle of the method and how to make the application in an environment with high scalability.

This page

Concurrency Problem Overview Data Update and Develop New DataSet and Re-Submit Updates Reissous, Refresh or Restore Insert and Delete Concurrent Form2 LOAD Event Process Multi-user Insertion Multi-User Delete Questions Summary

ADO.NET is specifically designed to improve scalability-especially suitable for data manipulation in the case where multiple users need to manipulate the same rows in the database table. A important feature of ADO.NET helps to increase scalability is that it relies on open and distribution to implement data manipulation.

Using an open concurrency, the user does not lock the row from the time you are ready to update a row. The row lock is only in ADO.NET to submit an instant application. Therefore, the other user can change the same row before the first user is submitted to the row. In this case, the first user performs the update to trigger the DBConCurrencyException object. ADO.NET provides features that help solve such problems. Multi-user issues may also affect the deletion and insertion of ADO.NET.

This article describes the encoding criteria for processing concurrency problems during the manipulation of data in ADO.NET. You will understand the context that caused concurrency issues and how to handle these issues for updates, insert, and delete them. By reviewing this topic, a set of core skills for handling basic concurrency issues, as well as the basis for increasing the skills of your more complex concurrent situation.

Concurrent problem overview

The reason for incompatibility as an ADO.NET is that the user is typically changed indirectly. ADO.NET connects the user to the database through the DataAdapter object, and the object rely on the Connection object. Users are not directly submitted to the database via DataAdapter, but change the local DataSet object. DataSet may contain one or more DataTable objects, and each DataTable may contain multiple DATAROW objects.

The DataAdapter object acts as a two-way pump between DataSet and the database. The ADO.NET solution can first populate DataSet with the DataAdapter's Fill method. After the user modifies one or more DATAROW objects in the DataTable within the DataSet, the application can call the DataAdapter's Update method to transfer these changes to the database. The UPDATE method is operated by DataAdapter's UpdateCommand, DeleteCommand, and INSERTCOMMAND attribute. These attributes represent the Command objects that package SQL Update, DELETE, and INSERT statements (or stored procedures).

When the ADO.NET application has multiple users, each user usually has access to a separate DataSet (and usually have access to separate DataAdapter). When multiple users can change DataSets at the same time, at least one DataSet may become simply synchronized with the database at least one DataAdapter. In this case, the DataAPter of Unchematically DataSet does not know which lines apply a group of changes. When the user calls the UPDATE method of the DataAdapter that is unconscious DataSet, ADO.NET will raise the DBConcurrencyException object to the first row with the unsynchronous value between DataSet and the database.

There are four possible DataRowVersion enumeration values, but the relationship between two DataRowVersion enumerations and basic concurrency issues are particularly close: Original and Current. ORIGINAL enumerates after the Fill method but is applied to DataRow before any changes to its column values. CURRENT is applied to DataRow before the value of one or more column values ​​is changed to the database. After successfully calling the update method with DataAdapter in DataTable, ADO.NET assigns the current value of DATAROW to the original value of the DataRow. For the design of the SQL Update, DELETE, and INSERT statements that are transferred from DataSet to the database, the reference to DataRow's original enumeration and Current enumerations are very critical. For example, the UPDATE statement uses the current value in its set clause, but the WHERE clause of the statement must contain references to the original value. DataAdapter can evaluate whether DataSet is still synchronized with the database.

Back to top

Data update concurrency

The module behind the FORM1 in the HCVSConcurrency project (which contains in the attached download file) can be changed by simulation of two users in the database, indicating that several encoding criteria for processing data modifications. This form uses the shippers table in the SQL Server Northwind database to enable changes to the COMPANYNAME column value containing the shipperid value 1.

To simplify the example, I created DataAdapter (SqlDataAdapter1) in a graphical way, which automatically pops updateCommand, DeleteCommand, and INSERTCOMMAND attributes to achieve open concurrency. Then, I generated three DataSets using the context menu of SqlDataAdPapter1, their Name attributes are DataSet1User11, Dataset1User21, and DataSet1FROMDB1, respectively. DataSet1User11 and DataSet1User21 DataSet are used for user 1 and user 2. Figure 1 shows the design of Form1, and the ADO.NET component is displayed in the component column below the form.

Back to top

Refresh DataSet and re-submit an update

Button1's Click event process is tried to update the database with TextBox1's Text property value. This process implements the changes made by the user 1. Button2's Click event process (for user 2) performs the same task for TextBox2. The second process demonstrates more mature techniques for processing open concurrent conflicts. When a user tries to modify the COMPANYNAME column value, the code behind Form1 began to modify the DataSet1User11 or DataSet1User21, and call the Update method of SqlDataAdapter1. If the change is successful, the code will clear CheckBox1, which is used to indicate an open concurrent conflict. If the modification fails, ADO.NET will trigger DBConcurrencyException and process the Exception object by a try ... catch ... finally statement.

The next code snippet (Load event process from Form1) initializes the DataSet of the user 1 and the user 2. Two Fill methods call the SQLDataAdapter1-based SelectCommand properties, fill two local DataSets with the value in the Northwind database. SelectCommand's SQL statement returns all three columns of the Shippers table for all rows. The code snippet also calls Refreshcontrols. SqlDataAdapter1.Fill (DataSet1User11)

SqlDataAdapter1.fill (Dataset1User21)

Refreshcontrols ()

The refreshcontrols process (which is displayed in the next code block) is called from the Form1 Load event process and the CLICK event of Button1 and Button2. The application fills the DataSet1FromDB1 DataSet via the refreshcontrols process. The code is then used in the assignment statement of Label1, TextBox1, and TextBox2, using the companyName column value in the first DataRow in DataSet 11FROMDB1. The expression of the Text property of each TextBox control is added 1 or 2 to the CompanyName column value. Note that in the following grammar, you can use the name or from zero-start index numbers to reference the columns in DataSet in DataSet.

Sqldataadapter1.fill (Dataset1FROMDB1)

Label1.text = "CURRENT DB VALUE:" & _

DataSet1FromDB1.Tables ("shippers"). _

ROWS (0) ("CompanyName")

TextBox1.text = dataset1user11.tables (0). _

ROWS (0) (1) & "1"

TextBox2.text = dataset1user21.tables (0). _

ROWS (0) (1) & "2"

The following codes are selected from the Click event process of Button1, which illustrates a simple way to coordinate open concurrent conflicts. As you can see, this statement actually contains two CATCH clauses. One is used for DBConcurrencyException objects, the second Exception object for any other kind of kind. Good programming criteria specify to use the final Catch clause to capture any exception objects captured in front of the more specific Catch clauses.

Try

DataSet1User11.shippers.Rows (0) (1) = _

DataSet1User11.shippers.Rows (0) (1) "1"

SqldataAdapter1.Update (Dataset1User11)

Checkbox1.checked = false

Catch ex as dbconcurrencyexception

SqlDataAdapter1.Fill (DataSet1User11)

DataSet1User11.shippers.Rows (0) (1) = _

DataSet1User11.shippers.Rows (0) (1) "1"

SqldataAdapter1.Update (Dataset1User11)

Checkbox1.checked = true

Catch exception

Str1 = ex.gettype.tostring & _

Controlchars.crlf & ex.Message

Messagebox.show (str1, "error form", _

MessageboxButtons.ok, MessageBoxicon.Error

Finally

Refreshcontrols ()

END TRY

The TRY clause of the try ... catch ... finally statement contains three statements. First, the code adds "1" to the value of the second column in the first row of the DataSet1User11's Shippers DataTable. Because all three applications Dataset are type, the code can be used as needed. TableName instead of .tables (TABLENAME). The second statement calls the UPDATE method of SqlDataAdapter1. If the UPDATE method is successful, the new value assigned to the DataSet will update the shippers table in the Northwind database. Control Subsequently passes the third statement in the TRY clause, which will clear CheckBox1.

If the user 2 updates the first line of the Northwind Shippers table since DataSet1User11 with the database value, when trying to call Update in the TRY clause, the DBConcurRencyException object will be triggered, and the control is passed to the first CATCH clause. . The code in this clause first refreshes DataSet1User11 with the Fill method of SqlDataAdapter1. Next, the example executes the same update as the TRY clause, but this time you know the DataSet value is synchronized with the database. The first CATCH clause end is ended by assigning a check mark to the Checkbox1.

Regardless of the success or failure of the UPDATE method, the Finally clause will run. The unique statement of the finally clause calls the refreshcontrols discussed earlier.

Back to top

Reissue, refresh or restore

Click Button2 immediately after clicking Button1, you can generate an open concurrency failure, which can cause the DBConcurrencyException object. This is because the first line of DataSet1User21 reflects the database before the Button1 implementation changes. Unlike an open concurrent conflict with the method demonstrated by the above code segment, Button2's Click event process enables users to choose from three possible solutions. Users can re-submit changes with refresh DataSet, or give up the changes but still refresh DataSet1User21, or restore the database to the original value of the first DATAROW in Shippers DataTable.

The application renders three options to users via InputBox. Figure 2 shows how Form1 looks after the first click Button1. Note that the form reports the current database value as Speedy Express1. The INPUTBOX below Form1 provides three options for resolving concurrent conflicts. Options Select to simplify in the TITLE of InputBox. These options are numbered 1, 2 and 3. Inputbox's body shows three values:

The Original property value of the second column in the first row of Shippers DataTable in DataSet1User21.

The current value of the second column in the DataTable.

The current Northwind database value of the companyName column in the first row of the ShipPers table.

The try ... catch ... Finally statement of the Button2 Click event process is exactly the same overall design with the Try ... catch ... Finally statement in the Button1 Click event. However, the CatCh clause of the DBConcurrencyException object is different. The following code snippet shows the 3 different techniques to process concurrent conflict DBConcurrencyException catch clauses. The code in the CATCH clause is divided into three parts. The first part is set and displayed inputbox. The second part is a SELECT CASE statement with a separate CASE clause corresponding to each of three different concurrent solution techniques. The last part consists of a single statement that assigns a check mark to Checkbox1. Each of the following item symbols summarizes the role of the CASE clause in the SELECT CASE statement. •

The CASE clause corresponds to the invutbox function value to refresh the DataSet1User21, make changes again, and then submit the change to the database by calling the UPDATE method of SqlDataAdapter1.

When the inputbox function returns a value 2, the SELECT CASE statement is just refreshed with DataSet1User21 without re-submitting the changes to the database. This option synchronizes DataSet1User21 with the database.

The InputBox function value 3 restores the original value in the DataSet1User 21 in the first DATAROW of ShipPers DataTable, and assigns the value to the corresponding column value in the Northwind Shippers table. The syntax of this method will be packaged in the ADO.NET Command object in the SQL UPDATE statement. This technology does not use SqlDataAdapter1 when the change is submitted to the database.

The final CASE ELSE clause capture any value other than 1, 2, and 3 provided to the INPUTBOX function.

Catch ex as dbconcurrencyexception

Str1 = "Value Summary:" & controlchars.crlf

STR1 & = "Original Value:" & _

DataSet1User21.shippers.Rows (0) _

("CompanyName", DataRowVersion.original).

Tostring & ControlChars.crlf

Str1 & = "Current Value:" & _

DataSet1User21.shippers.Rows (0) _

("CompanyName", DATAROWVERSION.CURRENT). _

Tostring & ControlChars.crlf

Sqldataadapter1.fill (Dataset1FROMDB1)

STR1 & = "Database Value:" & _

DataSet1FromDB1.Shippers.Rows (0) _

("CompanyName", DataRowVersion.current)

Str1return = INPUTBOX (str1, _

"1 RE-Submit Change, 2 Abort Change," & _

"3 restaurant ORIGINAL", "2")

SELECT CASE STR1RETURN

Case "1"

SqlDataAdapter1.fill (Dataset1User21)

DataSet1User21.Shippers.Rows (0) (1) = _MID (Dataset1User21.Shippers.Rows (0) (1), 1, _

Len (Dataset1User21.shippers.Rows (0) (1))

- 1) "2"

SqldataAdapter1.Update (Dataset1User21)

Case "2"

SqlDataAdapter1.fill (Dataset1User21)

Case "3"

DIM cmd1 as new sqlclient.sqlcommand

cmd1.connection = SQLConnection1

cmd1.commandtext = _

"Update Shippers Set CompanyName = '" & _

DataSet1User21.shippers.Rows (0) _

("CompanyName", DataRowVersion.original).

Tostring & "'Where Shipperid =" & _

DataSet1User21.shippers.Rows (0) _

("ShipperID", DataRowVersion.current). _

Tostring

cmd1.connection.open ()

cmd1.executenonquery ()

cmd1.connection.close ()

Case Else

Messagebox.show ("1, 2, or 3 only", _

"Warning Message", MessageboxButtons.ok, _

MessageBoxicon.information)

End SELECT

Checkbox1.checked = true

Back to top

Insert and delete concurrent

Concurrency problems or related types Consider except for updates, in addition to insertion and deletion. However, these issues have different forms and solutions (insertion and deletions are different from each other, and they are also different from the update). Figure 3 shows the Design view of the FORM2 in the HCVSConcurrency project. The project contains three TextBox controls for specifying the column values ​​to be added to the new row or specify the primary key of the rows to be deleted. Each of these two users has a row of buttons in the form. The first line is for users 1 to insert and delete rows, and refresh DataSet1User11 with database values. The second row button enables the same function as the user 2 and DataSet1User21. These buttons The DataGrid control under these buttons displays the current value in the Shippers table in the Northwind database.

The ADO.NET components created with graphics can be copied from Form1 to Form2 so that they can be used for FORM2. The Form2's LOAD event process designs a custom DataAdapter (DAP1) to insert a new line into the Northwind Shippers table. This custom DataAdapter code is interesting, there are two reasons. First, it illustrates the general design principles for creating DataAdapter preparing to use with DataSet. Second, it illustrates how to assign a value to a column with the Identity property setting, for example, the ShipperID column in the Shippers table.

Back to top

FORM2 LOAD Event Process

The code behind the FORM2 declares DAP1 at the module level. A common situation is a variable that needs to correspond to the ADO.NET class instance declared at the module level, because these instances are often used by two or more processes. The code used to specify the DAP1 DataAdapter has two parts. The start section assigns the value to the core properties of the DataAdapter. The second part demonstrates how to specify the parameters of the DataAdapter. The following code snippet assigns a value to the DAP1 property to use it in Form2. The instantiation statement of DAP1 reuses the SQLConnection1 object created in a graphical way to point DataAPter points to the Northwind database, and the SQL string specifies the base table connected to the DataAPter and the columns in the table. The assignment statement of the INSERTCOMMAND property of DAP1 contains two SQL statements. You can assign values ​​to the ShipperID column (which has an Identity property setting) via the Set Identity_Insert statement. The INSERT INTO statement specifies how to transfer the columns in the rows in the DataSet's shippers DataTable to the Shippers table in the Northwind database. Although the selectcommand property assigns SQLConnection1 to DAP1, it still needs to assign SQLConnection1 to the Connection member of InsertCommand in DAP1.

The three sets of assignment statements (corresponding to each parameter) are instantiated for parameters processing parameters in the INSERT INTO SQL statement. You need to add a parameter with the appropriate name and data type for each parameter in the SQL statement. Depending on the design of the application, you can use the SourceVersion property of the Parameter object to specify the current value of the DATAROW column value or the original value as the value of the parameter. The assignment statement of the @ShipperID parameter demonstrates the syntax for assigning the previous value, but in the context of this example, it is not absolutely necessary, because the current value of the column is the default parameter value.

DAP1 = New Sqlclient.sqldataAdapter_

("SELECT SHIPPERID, Companyname, Phone" & _

"From shippers", SQLConnection1)

Dap1.insertcommand = new sqlclient.sqlcommand _

("Set Identity_Insert Shippers on")

DAP1.INSERTCOMMAND.COMMANDTEXT & = _

INSERT INTO SHIPPERS & _

Shipperid, CompanyName, Phone "& _

Values ​​(@shipperid, @companyname, @Phone) "

Dap1.insertcommand.connection = SQLConnection1

DIM PRM1 As SqlClient.sqlparameter = _

Dap1.insertcommand.parameters.add_

("@Shipperid", sqldbtype.int)

prm1.sourceColumn = "shipperid"

prm1.sourceversion = DataRowVersion.current

DIM PRM2 As SqlClient.sqlparameter = _

Dap1.insertcommand.parameters.add_

("@Companyname", sqldbtype.nvarchar, 40) prm2.sourceColumn = "CompanyName"

DIM PRM3 as SqlClient.sqlparameter = _

Dap1.insertcommand.parameters.add_

("@Phone", sqldbtype.nvarchar, 24)

prm3.SourceColumn = "Phone"

Other FORM2 LOAD events in the following code snippet initialize the shippers DataTable in DataSet1User11 and DataSet1User21. These DataTable stores the Northwind Shippers table value of users 1 and user 2. DataSet1FROMDB1 is processed for the call to PopulategriDFromDB.

Dap1.fill (Dataset1User11, "Shippers")

DAP1.FILL (DataSet1User21, "Shippers")

PopulategridfromDB ()

The code in the populationGridFromDB process is then appeared. Its role is to refresh a DataSet and assign the DataSet to the DataSource property of the DataGrid control. When the data manipulation task includes insertion and deletion in addition to the update, it is only possible to obtain all changes to the DataSet invoking the Fill method. Although the Fill method can get an update, it cannot restore insertion and deletion of other users. Clear DATATABLE and reapperse the DataSet of the DataTable indefinite to get the complete new copy of the table from the database to reflect any new row or discarded rows since DataTable last refresh.

DataSet1FromDB1.Tables ("shippers"). Clear ()

DAP1.FILL (DataSet1FromDB1, "Shippers")

DataGrid1.datasource = _

DataSet1FromDB1.Tables ("shippers")

The end code snippet of the FORM2 LOAD event process assigns the default value to the TextBox1, TextBox2, and TextBox3 Text properties. These assignments are prepared to insert and delete the form immediately without changing the original column values ​​in the Northwind Shippers table. Moreover, the first statement reminds you to allocate the ShipperID column, for example, assign a value to its value 4.

TextBox1.text = "4"

TextBox2.text = "CAB, Inc."

TextBox3.text = "(123) 456-7890"

Back to top

Multi-user insertion

As long as you can guarantee that all new row inserts are unique, there will be no concurrent problems when the application tries to insert a new line into the database. However, this guarantee is not permitted to perform the inserted application. For example, the example insertion code in this section allows input of the Identity property value. Because the application simulates two users, each user may attempt to enter a row with the same Identity property value. Even if the two users do not specify a duplicate identity attribute value, a single user may also enter repetition values ​​for columns with unique constraints in DataTable. When trying to add a DataTable with a column value that matches the column value of another DATAROW, if the column has a unique constraint, the constraintException object may be triggered. These two types of errors should be considered when the design code is allowed to insert a new line. Button1 Click event procedure contains two order TRY ... CATCH statements - Each type error corresponds to a try ... catch statement. Before starting the error capture, the code creates a row value, which has the same design as columns in the shippers DataTable of DataSet1User11. The code is then filled with the column of the separated line with the value of the TEXTBOX control at the top of the FORM2.

Dim drw1 as dataAROW = _

DataSet1User11.tables ("shippers"). Newrow

DRW1 ("ShipperID") = integer.parse (TextBox1.text)

DRW1 ("CompanyName") = TextBox2.text

DRW1 ("Phone") = textbox3.text

The first TRY ... catch statement contains calls for the ADD method of the DataRowCollection member of the shippers DataTable in DataSet1User11. The add method tries to add a new line previously specified and fill. The DataRow column in the DataTable has a type and may be constrained. If these conditions are not met, it may cause an Exception (for example, constraintexception). The first TRY ... catch statement will detect such classes and other Exception objects.

Try

DataSet1User11.Tables ("shippers"). _

Rows.Add (drw1)

Catch exception

Str1 = ex.gettype.tostring & _

Controlchars.crlf & ex.Message

Messagebox.show (str1, "error form", _

MessageboxButtons.ok, MessageBoxicon.Error

END TRY

The second TRY ... catch statement detects the SQLException object generated by the primary key conflict. For ShipPers table, two different users allocate duplicate values ​​to the ShipperID column (for example, specifying the shipperid value 4), which will cause the ADO.NET to trigger the SQLException object of this type. You can use the CATCH statement for the WHEN clause to assess which SQL Server error indicating SQL Server Error. The parameter of the WHEN clause uses the INSTR function to search for text to represent the conflict of the primary key in the Message property value returned by the SQLEXCeption class.

Try

DAP1.UPDATE (DataSet1User11, "Shippers")

PopulategriDFromDB () catch ex askhen INSTR_SQLEXCEPTION WHEN INSTR_SQLEXCEPTION

(Ex.Message, "Violation of Primary Key"> 0

Handlepkviolation_

(Dataset1User11, DRW1 ("ShipperID"))

Catch exception

Str1 = ex.gettype.tostring & _

Controlchars.crlf & ex.Message

Messagebox.show (str1, "error form", _

MessageboxButtons.ok, MessageBoxicon.Error

END TRY

The above code snippet calls the handlepkviological process when the SQLException object with a message with the primary key conflict is detected. As you can see from the code snippet, the HandlePkViological process performs two tasks. First, it displays a message box to identify the problem and recommend one of two solutions. Second, it manipulates the ShipPers DataTable in the local DataSet (which is represented by a variable name named) to find and remove rows with repetition primary key.

Str1 = _

Primary Key Already in Database Table. "& _

"Modify Primary Key and Re-Submit OR" & _

"Abort Attempt to INSERT."

Messagebox.show (str1, "error form", _

MessageboxButtons.ok, MessageBoxicon.Error

DRW1 = Das.Tables ("shippers"). _

Rows.Find (PKValue)

Das.Tables ("shippers"). Rows.Remove (DRW1)

Figure 4 shows FORM2 and an error message about the primary key conflict. The form is displayed in its DataGrid control, and the ShipPers table contains a row with the ShipperID value 4. This line shows the contents of the TextBox control by clicking BUTTON1 (User 1 INSERT). Click Button2 (user 2 INSERT) to trigger the SQLException object caused by the primary key conflict. The above code snippet captures the error message and displays the message box (it appears in the bottom of Figure 4).

The code of the Button2 Click event process has the same general design as the code of the Button1 Click event process. The most significant difference is that the code manipulates DataSet1User21 instead of DataSet1User11. The handlepkviological process is designed to adapt to one of the two DataSets with different names. The more conventional design of this process can accommodate a variable DataTable name and a DataSet name.

Back to top

Multi-user deletion problem

DBConcurrencyException may be encountered when trying to delete rows from DataRow from DataSet DataTable. This happens when another user has previously deleted the same row since your local Dataset has previously refreshed. A particularly simple solution for concurrent errors in this context is to clear the DataSet and re-filled it according to the database. This operation can synchronize local DataSet with databases.

Like the inserted task, it is possible to generate another local error when trying to delete DATAROW from DataTable. This second error occurs when you try to delete a row that no longer exists. Common practices are to search for target DataRow in DataTable to avoid this type of error. If the search finds a match, the application can safely delete DataRow. Otherwise, the application can bypass the call to the Delete method because the target DataRow does not exist. The following code snippet in the Button4 Click event is displayed for logic for calling the delete method only when Datarow exists. This code snippet is used for user 2; Button3's Click event procedure has similar code for user 1. The first line assigns the return value of the Find method to the TextBox1's text property in the DataSet1User 21 of the TextBox1 in the DataRowCollection of Shippers DataTable. If the Find method finds that a DATARO has a primary key equal to the value equivalent value of the TEXT attribute value, the DRW1 variable is not empty. Otherwise, DRW1 (which has a DATAROW type) is Nothing. If DRW1 is not Nothing, the IF block calls DataRow's delete method. If DRW1 is Nothing, the ELSE block is just exiting the process.

DRW1 = DataSet1User21.tables ("shippers"). _

Rows.Find (INTEGER.PARSE (TEXTBOX1.TEXT))

IF not (drw1 is nothing) THEN

Drw1.delete ()

Else

EXIT SUB

END IF

When the code calls DataRow's Delete method, ADO.NET does not remove DataRow from DataTable. Instead, DataRow is just tagged to delete. When the code next time calls the DataTable DataSet container with the DataApter of the DataApter that is tagged to delete the DataApter, the DataAdapter will attempt to remove the corresponding row in the database. If the trial is successful, DataAdapter accepts changes in the DataSet. If the attempt fails due to some reason (for example, DBConcurrencyException objects), DataRow will remain in DataTable. The following code snippet in the Button4 Click event is displayed to test the syntax of the DBConcurRencyException object after calling the Update method that calls SqlDataAdapter1. If an exception occurs, the code first clears the DataSet and then re-filled DataSet1User21 with the Fill method.

Try

SqldataAdapter1.Update (DataSet1User21, _

Shippers

PopulategridfromDB ()

Catch ex as dbconcurrencyexception

DataSet1User21.clear ()

DAP1.FILL (DataSet1User21, "Shippers")

Before ending this section, I want to make a simple contrast to the Delete and REMOVE methods. The delete method is just tag DATAROW so that DataAdapter will remove it. The Remove method immediately removes DataRow from the DataTable DataRowCollection.

Back to top

summary

ADO.NET connects local DataSet to the database. This design function provides a huge scalability advantage that exceeds ADO (which is usually used by conservative concurrency). Although ADO.NET contains a wealth of features to simplify errors that may be generated by open concurrency, you still need some basic technologies. This article describes a series of code examples that demonstrate the basics of special technologies that you may feel useful when processing concurrent errors (also known as DBConcurrencyException objects). The HCVSConcurrency project provided in the download file contains all the techniques described herein and other technologies that have not been described due to the space limit. Download 409DObson.zip

For more information on Hardcore Visual Studio and Pinnacle Publishing, visit their Web site in http://www.pinpub.com/.

Note: This is not a Web site for Microsoft Corporation. Microsoft is not responsible for its content.

This article is reproduced from Hardcore Visual Studio 2004. Copyright 2004, Pinnacle Publishing, Inc. (unless otherwise stated). all rights reserved. Hardcore Visual Studio is a product of Pinnacle Publishing, Inc.. No part of this article is not used in any form without Pinnacle Publishing, Inc., except for any form of this article (except for short references in the comment). To contact Pinnacle Publishing, Inc., call 1-800-788-1900.

Go to the original English page

Back to top

转载请注明原文地址:https://www.9cbs.com/read-44386.html

New Post(0)