K
Ken Allen
I have been reading a lot of material on the use of (specifically) the
SqlClient classes that are used to retrieve, display, edit, and update
database records. The basic approach seems to be:
1. Define a SqlConnection to the database.
2. Define a SqlDataAdapter along with a command for retrieving the data.
3. Set the SqlDataAdapter.MissingSchemaAction to AddWithKey to ensure
Primary Key information will be included.
4. Define a DataSet and use SqlDataAdapter.Fill to populate it.
5. Associate the DataSet (or DataSet.Tables[0]) with a DataGrid or some
other control(s).
6. Permit the user to edit the contents of the DataSet; rows may be added,
deleted or modified.
7. Create a new SqlDataAdapter for the same command used to populate the
original data; again set the MissingSchemaAction to be complete.
8. Either define a SqlCommandBuilder or define commands for the Insert,
Delete and Update members of the SqlDataAdapter.
9. Invoke the SqlDataAdapter.Update method to commit all changes to the
database.
10. Some have suggested then using SqlDataAdapter.Fill on the same DataSet
to merge changes made by other clients with the existing information.
There seem to be a significant number of flaws with this approach, and it is
not easy to find discussions or suggestions for alternatives or methods to
avoid these flaws. Of course, I may be missing something completely and not
understanding how this process is actually working.
I want to make it clear that I develop client and client/server
applications. I have never developed IIS, IIS.Net or Web Service
'applications'.
Issue #1 -- This mechanism, as with the vast majority of the information I
can find on these specific classes, seem to presume single user access to
the database and, for the most part, ignore the impact of concurrent updates
from multiple client applications into the same database. Presuming the
above process is used concurrently by multiple client applications, all
making changes to the same table, there will be no way to control which
changes are made to a specific record! Consider the case where three (3)
clients make changes to the same record, where two of the changes are to
different columns and the third change involves all of the columns from the
first two. The first client issues the Update and the changes are saved; the
second client issues an Update and that change is saved, effectively
reversing the change from the first client; when the third client commits
the changes then both of the first two changes are overwritten -- and none
of the clients are aware of this.
Issue #2 -- The documentation indicates that repeating the
SqlDataAdapter.Fill method call on an existing DataSet will merge the
changes from the table into the DataSet, but this is only partially true --
it does not seem to deal with records that are in the DataSet but which have
been deleted from the database table (likely by another client). In order to
achieve this it seems one should issue a DatSet.Tables[0].Clear method call
before the SqlDataAdapter.Fill call to ensure that this happens, although
none of the documentation mentions this.
Issue #3 -- I have found no references to how one might effectively approach
dealing with the situation where multiple records are modified in different
ways by different concurrent users. Considert the case where client A and
client B both retrieve the same set of records from the same table. Client A
modifies one record and saves the change (the Update succeeds). Client B at
that point has no understanding that changes have been made, and the client
makes changes to several records, including the one changed by client A. It
is not clear how the Update could permit the changes to be made to all of
the records except the one modified by Client A (or even how this would be
detected), and then permit this information to be reported back to client B.
The only option seems to be to fail the entire update from Client B, but
there is still no clear way to explain which records are affected. This is
compounded by the indication that if the Update method succeeds the
AcceptChanges method on the DataSet seems to be called.
Issue #4 -- There does not seem to be any automatic way to indicate, say in
a DataGrid, which records have been modified and which have not. There also
does not seem to be an automatic way to indicate that some record changes
were committed to the database and other changes were not.
Issue #5 -- These issues are compounded when the code is implemented in a
client/server architecture as opposed to a single application (or in a web
application, although I have not personally written any of those).
Issue #6 -- While there is documentation on the SqlDataAdapter.RowUpdating
event, there is no information on how (or if) the code can indicate that the
specific record can be ignored or skipped. Ideally it would be nice to be
able to compare the original record in the DataSet with the current content
of the database table and reject the record accordingly. In order for the
client to understand what happened, one would likely want to retain the
modified record from the DataSet so it can be compared to the new version
from the table and shown to the user (permitting them to make more changes
without having to memorize the specific change they made).
Issue #7 -- There is no documentation on how the Fill and Update method
processes play together when executed against the same table from different
client applications concurrently. Consider the scenario from issue #1 and
attempt to define the specific data values that each of the three clients
will see on their screen.
Issues #8 -- The existing classes and controls seem to be focused solely
upon multiple-record updates. There seems to be little attention paid to
scenarios where the change to each individual record must be processed
before the user can make changes to other records. I know that much of .Net
is geared toward IIS.Net and Web Server applications, but many client/server
applications have traditionally dealt with single record processing, at
least in part to avoid some of the problems that are discussed above. I am
willing to convert to this 'batch' mode of processing, but I cannot see the
degree of control that I need.
I apologize of some of the comments here are not crystal clear.
-ken
SqlClient classes that are used to retrieve, display, edit, and update
database records. The basic approach seems to be:
1. Define a SqlConnection to the database.
2. Define a SqlDataAdapter along with a command for retrieving the data.
3. Set the SqlDataAdapter.MissingSchemaAction to AddWithKey to ensure
Primary Key information will be included.
4. Define a DataSet and use SqlDataAdapter.Fill to populate it.
5. Associate the DataSet (or DataSet.Tables[0]) with a DataGrid or some
other control(s).
6. Permit the user to edit the contents of the DataSet; rows may be added,
deleted or modified.
7. Create a new SqlDataAdapter for the same command used to populate the
original data; again set the MissingSchemaAction to be complete.
8. Either define a SqlCommandBuilder or define commands for the Insert,
Delete and Update members of the SqlDataAdapter.
9. Invoke the SqlDataAdapter.Update method to commit all changes to the
database.
10. Some have suggested then using SqlDataAdapter.Fill on the same DataSet
to merge changes made by other clients with the existing information.
There seem to be a significant number of flaws with this approach, and it is
not easy to find discussions or suggestions for alternatives or methods to
avoid these flaws. Of course, I may be missing something completely and not
understanding how this process is actually working.
I want to make it clear that I develop client and client/server
applications. I have never developed IIS, IIS.Net or Web Service
'applications'.
Issue #1 -- This mechanism, as with the vast majority of the information I
can find on these specific classes, seem to presume single user access to
the database and, for the most part, ignore the impact of concurrent updates
from multiple client applications into the same database. Presuming the
above process is used concurrently by multiple client applications, all
making changes to the same table, there will be no way to control which
changes are made to a specific record! Consider the case where three (3)
clients make changes to the same record, where two of the changes are to
different columns and the third change involves all of the columns from the
first two. The first client issues the Update and the changes are saved; the
second client issues an Update and that change is saved, effectively
reversing the change from the first client; when the third client commits
the changes then both of the first two changes are overwritten -- and none
of the clients are aware of this.
Issue #2 -- The documentation indicates that repeating the
SqlDataAdapter.Fill method call on an existing DataSet will merge the
changes from the table into the DataSet, but this is only partially true --
it does not seem to deal with records that are in the DataSet but which have
been deleted from the database table (likely by another client). In order to
achieve this it seems one should issue a DatSet.Tables[0].Clear method call
before the SqlDataAdapter.Fill call to ensure that this happens, although
none of the documentation mentions this.
Issue #3 -- I have found no references to how one might effectively approach
dealing with the situation where multiple records are modified in different
ways by different concurrent users. Considert the case where client A and
client B both retrieve the same set of records from the same table. Client A
modifies one record and saves the change (the Update succeeds). Client B at
that point has no understanding that changes have been made, and the client
makes changes to several records, including the one changed by client A. It
is not clear how the Update could permit the changes to be made to all of
the records except the one modified by Client A (or even how this would be
detected), and then permit this information to be reported back to client B.
The only option seems to be to fail the entire update from Client B, but
there is still no clear way to explain which records are affected. This is
compounded by the indication that if the Update method succeeds the
AcceptChanges method on the DataSet seems to be called.
Issue #4 -- There does not seem to be any automatic way to indicate, say in
a DataGrid, which records have been modified and which have not. There also
does not seem to be an automatic way to indicate that some record changes
were committed to the database and other changes were not.
Issue #5 -- These issues are compounded when the code is implemented in a
client/server architecture as opposed to a single application (or in a web
application, although I have not personally written any of those).
Issue #6 -- While there is documentation on the SqlDataAdapter.RowUpdating
event, there is no information on how (or if) the code can indicate that the
specific record can be ignored or skipped. Ideally it would be nice to be
able to compare the original record in the DataSet with the current content
of the database table and reject the record accordingly. In order for the
client to understand what happened, one would likely want to retain the
modified record from the DataSet so it can be compared to the new version
from the table and shown to the user (permitting them to make more changes
without having to memorize the specific change they made).
Issue #7 -- There is no documentation on how the Fill and Update method
processes play together when executed against the same table from different
client applications concurrently. Consider the scenario from issue #1 and
attempt to define the specific data values that each of the three clients
will see on their screen.
Issues #8 -- The existing classes and controls seem to be focused solely
upon multiple-record updates. There seems to be little attention paid to
scenarios where the change to each individual record must be processed
before the user can make changes to other records. I know that much of .Net
is geared toward IIS.Net and Web Server applications, but many client/server
applications have traditionally dealt with single record processing, at
least in part to avoid some of the problems that are discussed above. I am
willing to convert to this 'batch' mode of processing, but I cannot see the
degree of control that I need.
I apologize of some of the comments here are not crystal clear.
-ken