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

Professional ASP.NET 1.0 Special Edition- P16 pdf

40 199 0

Đ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 40
Dung lượng 1,18 MB

Nội dung

'now we can check if the values are valid If objRow("ISBN", DataRowVersion.Proposed) > "1999999999" Then objRow.CancelEdit() Else objRow.EndEdit() End If 'then display the contents again dgrResult3.DataSource = objTable.DefaultView dgrResult3.DataBind() To demonstrate the effect of the EndEdit method, the next section of code just repeats the whole process - but this time it sets the value of the ISBN field to a number less than "1999999999" so that the test succeeds This means that this time the EndEdit method is called Again, the contents of the table are displayed during and after the edit process: The Original, Current, and Proposed Column Values If you were on your toes when reading the previous code listing, you'll have seen that we used a special syntax when accessing the value of a column: If objRow("ISBN", DataRowVersion.Proposed) > "1999999999" Then As we'll see in more detail in the next chapter, every column in every row of a table maintains three values for that item These values are defined in the DataRowVersion enumeration, and they are used to help maintain concurrency when updating data: The value that was in the column when the DataTable was created and filled with data It is compared to the Original value in the original database table when an update is performed, to see if another user or process has changed the value since the DataTable data was created Proposed The proposed value for this column after changes have been made following BeginEdit, but before EndEdit¸ CancelEdit, AcceptChanges* or RejectChanges* has been executed The actual column value after changes have been made to it, and after these changes have been accepted Current (after EndEdit or AcceptChanges* has been executed) * The AcceptChanges and RejectChanges methods are described next Accepting and Rejecting Changes in a Row, Table, or DataSet As we saw earlier, we can access any of the three values that are stored for every column in every row of a table at any time to get the appropriate value for a comparison test, or to check whether values in a row have been changed or are in the process of being changed As well as using the BeginEdit, EndEdit, and CancelEdit methods to manage updates to a table row, we can also use the AcceptChanges and RejectChanges methods Their actions are self-explanatory, with AcceptChanges effectively calling EndEdit on any rows that are currently being edited, and RejectChanges effectively calling CancelEdit on any rows that are currently being edited As far as the DataRow object is concerned: After execution of the BeginEdit method, if you change the value in any column, the Current and Proposed values of all the columns become accessible The Proposed value is the same as the Current value until you edit that particular column After execution of the EndEdit method, the Current value for each column is replaced by the Proposed value After execution of the CancelEdit method, the Proposed value is discarded and the Current value is unchanged After execution of the AcceptChanges method, the Original value for each column is replaced by the Current value After execution of the RejectChanges, the Current value is discarded and the Original value is unchanged Notice that the effects of the AcceptChanges and RejectChanges methods are subtly different from BeginEdit, EndEdit, and CancelEdit The AcceptChanges and RejectChanges methods affect the Current and the Original values (rather than the Current and Proposed values) The AcceptChanges and RejectChanges methods can also be used at DataTable and DataSet level After execution of the DataTable (rather than the DataRow) object's AcceptChanges method, the Original value for every column in all rows in the table is set to the same as the Current value After execution of the DataSet object's AcceptChanges method, the Original value for every column in every row in all tables in the Dataset is set to the same as the Current value It's important not to call these methods on a DataSet or a DataTable if you intend to update the original source data from the DataSet object, as it depends on the difference between the Original and Current values to be able to correctly detect any concurrency errors We look at this topic in detail in the next chapter The RowState Property of the DataRow Object Each row in a table exposes another useful property named RowState This is related to inserting, editing, and deleting rows in a table, and provides a useful indication of the current state of each row The DataRowState enumeration provides the following values: Value Description No changes have been made to the row since it was created or since the last call to the AcceptChanges Unchanged Added method of the row, table, or DataSet The row has been added to the table and AcceptChanges has not yet been executed At least one value or property of the row has been changed since the last call to the AcceptChanges Modified method of the row, table, or DataSet The row has been deleted from the table using the Delete method and AcceptChanges has not yet been Deleted executed The row has been created with the NewRow method but has not yet been added to the table with the Add Detached method Hence, it is not actually classed as being a row within that table We can access the RowState property at any time to see the state of any row However, it is most useful when we come to update the original source data We'll see this in the next chapter Deleting and Removing Rows from a DataTable Deleting a row from a table is easy - we just call the Delete method of the DataRow object we want to delete We can specify the index of the row to delete within the Rows collection: 'delete first and third rows in table referenced by objTable objTable.Rows(0).Delete() objTable.Rows(2).Delete() Or we can use a reference to the actual DataRow object we want to delete: objThisRow.Delete() objOtherRow.Delete() The rows we delete remain in the table All the Delete method does is set the RowState property to DataRowState.Deleted (as we saw in the previous section) However, next time we call AcceptChanges for the table, or for the DataSet object that contains the table, the row is removed from the table This means that we can "undelete" rows simply by calling RejectChanges instead of AcceptChanges So, we can write code to delete some rows (or update and insert rows for that matter) in a table, and then carry out some comparison tests to decide whether to accept or reject all the changes in one go Of course, (as we saw a little earlier) we can access the appropriate DataRowVersion for each column as we so to get the Original, Current, or Proposed value Removing Versus Deleting Rows As an alternative to deleting a row in a table, we can remove it instead This is an entirely different process from deleting a row When we execute the Remove method we immediately and irretrievably remove the row from the table in the DataSet It isn't marked as deleted - it just disappears from the table As a result, the row indices also change to reflect the new "row positions" as they all shuffle up to fill the gap left by the row that was removed: 'remove the third row from the table objTable.Rows.Remove(2) 'using the Remove method on row (rather than marking it as deleted 'with the Delete method) means that the next row then becomes row 'so, to remove the next row from the table as well we repeat the use of objTable.Rows.Remove(2) If you intend to use the DataSet to update the original data store, avoid using Remove to delete rows Always use the Delete method so that the rows remain in the table but are marked as being deleted These "deletes" will then be made in the original data source when you call the Update method Notice the difference in syntax The Delete method is a member of the DataRow object The Remove method is a member of the Rows collection To see how the Delete and Remove methods work, you can try the example "Removing versus Deleting Rows in a DataTable" (remove-delete-rows.aspx): The Code for the Delete versus Remove Example The code in this example is relatively straightforward We create a new DataSet and insert three rows into it using the same kind of code as in earlier examples: 'create a new empty Table object Dim objTable As New DataTable("NewTable") 'fill table with three new rows using code here ' All these rows will now have a RowState property of DataRowState.Added So we next call the AcceptChanges method to "fix" (accept) these changes - which updates the RowState property of all the rows to DataRowState.Unchanged Then we display the contents of the table: 'call AcceptChanges to accept the changes to the table so far objTable.AcceptChanges() 'assign the DataTable's DefaultView object to the DataGrid control dgrResult1.DataSource = objTable.DefaultView dgrResult1.DataBind() 'and bind (display) the data Now we call the Delete method on the second row, and then display the contents again The RowState property of the deleted row is set to DataRowState.Deleted and it disappears from view: 'now Delete the second row and display the contents again objTable.Rows(1).Delete() dgrResult2.DataSource = objTable.DefaultView dgrResult2.DataBind() However, the next line of code calls the RejectChanges method of the table, and then displays the contents again The RowState property of the deleted row is set back to DataRowState.Unchanged and it reappears in the table: 'call RejectChanges to restore the deleted row objTable.RejectChanges() dgrResult3.DataSource = objTable.DefaultView dgrResult3.DataBind() Now we call the Remove method of the Rows collection of the table, specifying the second row as the one to be removed Then we display the contents of the table again to show that it has been removed: 'now Remove the second row from the table 'note that this is a method of the Rows collection not the Row object objTable.Rows.Remove(1) dgrResult4.DataSource = objTable.DefaultView dgrResult4.DataBind() Finally, we call the RejectChanges method of the table However, this time, the row does not reappear It has been permanently removed from the table and cannot be restored: 'call RejectChanges - the deleted row is not restored objTable.RejectChanges() dgrResult5.DataSource = objTable.DefaultView dgrResult5.DataBind() Working with DataTable Events The DataTable object exposes a series of events that we can use to monitor changes to the content of a table in a DataSet The ColumnChanging event is raised for a column in a row that is being edited, before the change is applied to that column (allowing the change to be cancelled) The ColumnChanged event is raised after the column has been changed and the change has been persisted to the column There are also events that occur for the row as a whole, rather than for each column in a row The RowChanging and RowChanged events are raised when the content of any row in the table is changed - the first event occurring before the change is applied to the row (allowing the change to be cancelled) and the second event occurring after the change has been persisted in the table Finally, there are two events that occur when a row is deleted from a table The RowDeleting event occurs before the row is deleted, allowing the deletion to be cancelled, and the RowDeleted event occurs after the row has been deleted from the table We don't have room to demonstrate all these events - however, we will show you an example of how they can be used Using the RowUpdated Event The example page "Validating Edits in a Table with the RowUpdated Event" (update-check-errors.aspx) demonstrates how we can use the RowUpdated event of a DataTable object to validate the values that are entered into each row Code in this page fills a DataSet object with data from our sample database and then changes the values in two rows It then displays the changed rows in a DataGrid: At the bottom of the page, you can see that two errors have been reported We placed an event handler in the page that detects when a row is updated, and it applies a couple of simple validation rules to the data in the row Code in the page then checks the data for errors, and summarizes any it finds The Code for the Validating Edits Example We've used the same techniques as most of the earlier examples to fill our DataSet with a table named "Books" containing details of several books from our example database We aren't repeating this code here After filling the DataSet, we call the AcceptChanges method to "fix" the current contents: 'accept changes to "fix" current state of the DataSet contents objDataSet.AcceptChanges() Now we can set up the event handler we need to react to the RowChanged event We use the AddHandler method in Visual Basic, specifying the event we want to react to and the name of the event handler ("OnRowChanged") that is defined elsewhere in the page: 'set up event handler to react to changes to rows in the table Dim objTable As DataTable = objDataSet.Tables("Books") AddHandler objTable.RowChanged, _ New DataRowChangeEventHandler(AddressOf OnRowChanged) In C#, we would add the same event handler using: objTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged) This event handler will be called when any row is updated, after the changes have been applied to it In our handler code we apply our simple validation rules If the update is not valid, we need to be able to flag this up - though we don't actually want to it at this point We want to be able to detect errors at some point in the future, perhaps before we submit the DataSet back to the database to update the original data If we only wanted to flag up errors at the point when the user entered them, we could validate the values in the page where they were entering the data Row Errors and DataRow Actions "Title LIKE '*ASP*' AND StockQty > 1000" "(LastName = 'Smith' OR LastName = 'Jones') AND FirstName = 'John'" The following characters cannot be used directly in a column name within a filter expression: ~ ( ) # \ / = > < + - * % & | ^ ' " [ ] If a column name contains one of these characters or a space, it must be enclosed in square brackets: "[Stock#] > 1000" 'column named "Stock#" If a column name contains a closing square bracket this must be escaped with a preceding backslash: "[Number[\]Cols] > 1000" 'column named "Number[]Cols" There is also a range of functions supported in filter expressions, including: Sum, Avg, Min, Max, Count, StDev, Var, Convert, Len, IsNull, IIF, SubString For more information, search the NET SDK for "column and filter expressions" The Code for the DataTable Sorting and Filtering Example We can now look at the code for the example page we saw a little earlier It contains a that holds the command buttons and text box for the filter expression, and this is followed by a where the results are displayed: Sort records:    

Search within titles: The code then goes off and collects a subset of rows from the original data store - our SQL Server database It places them in a table named Books within a DataSet This table contains all the books you saw in the first screenshot for this example Then we can create the filter and/or sort expressions provided by the user In the case of a filter expression, we add a preceding and trailing asterisk wildcard character so that it will match column values containing this text: 'create the Sorting expression Dim strSortString As String = "" If Len(Request.Form("cmdTitle")) > Then strSortString = "Title" If Len(Request.Form("cmdISBN")) > Then strSortString = "ISBN" If Len(Request.Form("cmdDate")) > Then strSortString = _ "PublicationDate DESC, Title" 'or create the Filter expression Dim strFilterExpr As String = "" If Len(Request.Form("cmdFind")) > Then strFilterExpr = "Title LIKE '*" & txtFind.Value & "*'" End If If this is the first time that page has been loaded, there will be no values from the in the request, and so no filter or sort expression will be created Otherwise, after the code above has been executed, we'll have one or the other in the strings strSortString and strFilterExpr We display these values in another element placed before the section of the page: 'display the parameters we're using outMessage.innerHTML = "Called DataTable.Select(""" _ & strFilterExpr & """, """ & strSortString & """)" Now we can apply the filter or sort to the table We first get a reference to the DataTable object: Dim objTable As DataTable = objDataSet.Tables("Books") Executing the Select Method The Select method returns an array of DataRow objects that match the filter and sort we apply, so the next step is to create a suitable array variable Then we can execute the Select method and assign the result to this variable: 'create an array to hold the results then call the Select method Dim objResults() As DataRow objResults = objTable.Select(strFilterExpr, strSortString) Displaying the Results To display the results, we have to iterate through the array of DataRow objects that is returned by the Select method - we can't just bind it to a DataGrid as we've done in earlier examples In our example, we build an HTML table containing the column values for each DataRow in the array and then display this table in the element named outResult: 'the result is an array of DataRow objects not a DataTable object 'so we have to iterate through to get the row contents Dim objRow As DataRow Dim strResult As String = "" For Each objRow In objResults strResult += "" & objRow(0) & "  " & objRow(1) _ & "  " & objRow(2) & "" Next strResult += "" outResult.InnerHtml = strResult 'and display the results Sorting and Filtering in a DataView Object Another opportunity for sorting and filtering rows for display is within a DataView object It's common to create a DataView based on a DataTable when using server-side data binding - as we've been doing throughout these chapters with a DataGrid server control The example page "Sorting and Filtering Records in a DataView object" (sort-find-in-dataview.aspx) demonstrates how easy it is to sort and filter the rows in a DataView The page looks similar to the previous example of sorting and filtering a DataTable However, notice the code that has been executed after we clicked the "By Date" button this time: Rather than using a Select method, as we did with the DataTable, we specify the filter and sort order for a DataView by setting its properties We set the Sort property to change the sorting order of the rows, and the RowFilter property to apply a filter The next screenshot shows the result of entering the search text ASP and clicking the Find button: As we saw earlier in the example of using the RowUpdated event, the DataView object also has a RowStateFilter property This works just the same as with the DataTable object, and we can also use this to filter the rows The Code for the DataView Sorting and Filtering Example As you'll expect, most of the code for this example is the same as we used in the previous example It uses the same HTML form and the same code to create and fill a DataSet with some book details However, the next step is to get a reference to the DataView object that we'll be working with In our example, we're creating a new DataView based on the Books table in the DataSet: 'create a DataView object for the Books table in the DataSet Dim objDataView As New DataView(objDataSet.Tables("Books")) Of course, if you already have a DataTable object available, perhaps as the result of some other code you've used to create it specifically, you can simply access the DefaultView property of the table to get back a DataView object Collecting the User's Values and Applying the Sort and Filter Now we can check for user input and build the appropriate string for the Sort and RowFilter properties of the DataView If the user clicked a 'sort' button, we simply build the sort expression as one or more column names (including "DESC" for a descending sort order) and set the Sort property of the DataView object We also display the code we're using: 'sort the records into the correct order If Len(Request.Form("cmdTitle")) > Then objDataView.Sort = "Title" outMessage.innerHTML = "DataView.Sort = " & objDataView.Sort End If If Len(Request.Form("cmdISBN")) > Then objDataView.Sort = "ISBN" outMessage.innerHTML = "DataView.Sort = " & objDataView.Sort End If If Len(Request.Form("cmdDate")) > Then objDataView.Sort = "PublicationDate DESC, Title" outMessage.innerHTML = "DataView.Sort = " & objDataView.Sort End If If the user clicked the Find button, we build a filter expression (using the same syntax as the previous example), and assign it to the RowFilter property of the DataView object As in the previous example, we add a preceding and trailing asterisk wildcard character so that it will match column values containing this text We also display the expression we're using in the page: 'or find matching records If Len(Request.Form("cmdFind")) > Then objDataView.RowFilter = "Title LIKE '*" & txtFind.value & "*'" outMessage.innerHTML = "DataView.RowFilter = " & objDataView.RowFilter End If Finally, we can assign our sorted or filtered DataView object to the DataSource property of an ASP.NET DataGrid control declared elsewhere in the page to display the contents: 'assign the DataView object to the DataGrid control dgrResult.DataSource = objDataView dgrResult.DataBind() 'and bind (display) the data Summary In this chapter, we've looked at all the important topics regarding working with data within the three fundamental NET data access objects - the DataReader, the DataTable, and the DataSet objects We've seen how we can extract data from a data store using complex SQL statements and different types of stored procedures We've also seen how we can build DataSet and DataTable objects from scratch using code, and then set a range of properties on each data column to accurately specify their behavior Then we moved on to look at how we can add, delete, edit, and completely remove rows in a table We examined the various properties that indicate the state of each row and each column in that row, and saw how we can cancel changes to a row, a table, and a complete DataSet object Finally, we looked at a couple of ways that we can filter and sort data - in a DataTable object and in a DataView object The topics we covered as a whole were: Accessing complex data with DataReader and DataSet objects Using stored procedures with DataReader and DataSet objects Building and editing data in a DataTable object Sorting and filtering data with DataTable and DataView objects Now that you are comfortable with the way that NET data access works, and the fundamental objects, their common properties and methods, it's time to look at the final major relational data topic How we go about updating the original data in our database or other data store? This is the core topic of the next chapter Updating Relational Data Sources In the previous two chapters, we've explored how we use the major objects within the NET framework for relational data access This includes the DataReader, Connection, Command, DataAdapter, DataTable, and DataSet objects We also explored the use of subsidiary objects such as the DataRelation, DataRow, Parameter, and others We've seen how we can use these objects in a range of combinations to extract data from a relational data store and work with that data The techniques we demonstrated included examination of the ways we can update the data that we hold within the confines of the disconnected DataSet objects that we created What we haven't looked at is how we perform that final step required in any application used fundamentally for updating a data store - how we push our changes back into the data store Even in a connected environment, such as a traditional client-server application, the process of managing updates to the source data is not without its own problems, in particular the managing of concurrent updates to the source data While NET does not introduce any new problems, the concept of working with data in a fundamentally disconnected way (such as NET provides) means that you need to be fully aware of the issues and know how to handle them This is the core topic of this chapter We'll be looking at: Updating data sources with a Command object Using transactions when updating data sources Updating data sources from a DataSet object A detailed look inside the DataAdapter.Update method Managing concurrent updates to a data source Obtaining the Sample Files All the examples used in this chapter are available for you to run on your own server The download file can be obtained from http://www.wrox.com/Books/Book_Details.asp?isbn=1861007035, and it includes SQL scripts and instructions for creating the database that the examples use You can also run some of the examples on-line at http://www.daveandal.com/profaspnet/ The main menu page (default.htm) contains links to all the data access sample files The fourth link, "Updating Relational Data Sources in NET" leads to another menu page that contains links to the examples for this chapter: Updating Data with a Command Object For simple single or multiple row updates to a data store, we traditionally used an ADO Connection or Command object with a SQL statement or a stored procedure This technique is particularly useful for tasks like inserting a new row into a database, perhaps in response to a user submitting feedback to your web site or registering for your monthly e-mail bulletin It's also useful for the equivalent 'delete' operation to remove one or more rows, or for updating row values Under the NET framework, we can the same thing using one of the new Command objects The SqlCommand object is used only with Microsoft SQL Server (via TDS), while the OleDbCommand object can be used for any type of data store for which an OLEDB provider is available We provide two pages that demonstrate the technique - one that uses a SQL UPDATE statement to modify a row in the database, and one that uses a stored procedure within the database to add a new row or delete an existing row Like all the examples, they develop on the techniques that we've covered in the previous data access chapters, and so we'll be concentrating on the new features that the examples introduce, and the code we use to implement these features Using a Command Object with a SQL Statement The simplest way to perform a quick update to a data source is to create a suitable SQL statement and then execute it against that data source using a Command object The example page Updating Data with a Command Object (update-with-command.aspx) does just that When you open the page, code in the Page_Load event handler creates a SQL UPDATE statement that changes the title of a book with a specified ISBN code in our BookList table: Remember that all the example pages have a [view source] link that you can use to view the sourcecode of the page The SQL statement we use is visible in the screenshot, and you can see that one row was affected by the execution of that statement The code in the page then uses a DataReader object with the same connection to read back the newly updated row from the source table and display the values The Code for the SQL Statement Update Example As with most of the examples in previous chapters, the pages in this chapter work with a database named WroxBooks and the connection string specified in the user control named connect-strings.ascx (in the global folder of the data access samples) See the previous chapters for more details The first section of code that interests us here is how we create the SQL statement that will update the book title We've included the current date and time in the title so that it changes every time you run the page: 'specify the SQL statement to update the data Dim datNow As DateTime = Now() Dim strNow As String = datNow.ToString("dd-M-yy \a\t hh:mm:ss") Dim strSQL As String strSQL = "UPDATE BookList SET Title = 'New Book Written on " _ & strNow & "' WHERE ISBN='1861009999'" outSQL.InnerText = strSQL 'and display it After displaying the SQL statement in a element named outSQL (elsewhere in the page), we create a new Connection object using our previously obtained connection string Then we specify this Connection and our SQL statement in the constructor for a new Command object We also declare an Integer variable to hold the number of rows that are updated: Dim objConnect As New OleDbConnection(strConnect) Dim objCommand As New OleDbCommand(strSQL, objConnect) Dim intRowsAffected As Integer Executing the SQL Statement Now we can execute the command We open the connection to the database, and then call the ExecuteNonQuery method of the Command object This method is used whenever we don't expect to get a rowset back It returns the number of rows affected by the execution of the statement, and we capture this in our intRowsAffected variable: Try objConnect.Open() intRowsAffected = objCommand.ExecuteNonQuery() Catch objError As Exception 'display error details outError.InnerHtml = "* Error while updating original data." _ & objError.Message & "" & objError.Source Exit Sub ' and stop execution End Try Provided that we didn't get an execution error (if we do, the Try Catch construct will display the error and stop execution of the code), we can display the number of rows that were updated: 'declare a string to display the results Dim strResult As String 'show the number of rows affected strResult = "Executed SQL statement, " & intRowsAffected.ToString() _ & " record(s) affectedReading back from the database " Displaying the Updated Row Now we can read the updated row back from the database to prove that the process worked We create a suitable SQL SELECT statement and assign it to the CommandText property of our existing Command object Then we declare a variable to hold a DataReader object, and execute the SELECT statement The result is obtained by reading the rows returned by the DataReader (we demonstrated this technique several times in previous chapters): objCommand.CommandText = "SELECT * FROM BookList WHERE ISBN='1861009999'" Try Dim objDataReader As OleDbDataReader objDataReader = objCommand.ExecuteReader() Do While objDataReader.Read() strResult += "ISBN=""" & objDataReader("ISBN") _ & """   Title=""" & objDataReader("Title") & """" Loop objDataReader.Close() objConnect.Close() Catch objError As Exception 'display error details outError.InnerHtml = "* Error while accessing updated data." _ & objError.Message & "" & objError.Source Exit Sub ' and stop execution End Try Finally, we display the contents of the updated row that we captured in the 'result' string in another element named outResult: outResult.InnerHtml = strResult 'display the result So, using a SQL statement and Command object to modify the contents of a data store is very similar to the way we would ... If you were on your toes when reading the previous code listing, you''ll have seen that we used a special syntax when accessing the value of a column: If objRow("ISBN", DataRowVersion.Proposed)... literals in single quotes "StockQty > 1000" ''numbers are not in quotes "PublicationDate > #10/10/99#" ''special syntax for date/time The supported comparison operators are: , =, , =, IN and... Finally, we can assign our sorted or filtered DataView object to the DataSource property of an ASP.NET DataGrid control declared elsewhere in the page to display the contents: ''assign the DataView

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