G
Guest
Hello,
I have a pretty difficult question about a hard-to-explain issue (I hope my
English would be good enough to make you understand). The environment beside
the problem itself may also be important, so I'm gonna explain a little the
whole idea and then go back to the issue and my question. Thanks in advance
for your time.
I am developing a .NET 1.1-based application that uses a main central
DataSet instance as a local cache storage for the current user-based slice of
data stored in an SQL Server database. The application consists of several
threads that may access the DataSet either to retreive data or for updating
data.
A special thread in the application is set to listen to all DataSet's
tables' RowChanged and RowDeleted events through a single event handler that
does something like this:
public void RowChanged(object sender, DataRowEventArgs e)
{
lock (myDataSet)
{
DataSet changes = myDataSet.GetChanges();
if (changes != null)
{
myDataSet.AcceptChanges();
//... Store changes in a changes queue, for later use in background
synchronization to the SQL Server database (using multiple
DataAdapter.Update() commands, one for each DataTable in the DataSet)
}
}
}
All the other threads that use the DataSet are using a lock(myDataSet) block
in order to maintain thread safety of the operations.
The idea here is to get all the changes that are done to the local DataSet
in a one-by-one way, so that I can update them back to the SQL Server (like a
"replication" synchronization) in a background thread and do not affect the
user's experience in that process.
Some would argue about the comment above that it won't be necessary to get
the changes one-by-one as I could from time to time execute a
myDataSet.GetChanges() in the background thread itself and update all the
changes back to the database at once -- however, this is not true because I
have circular relationships between the database tables, and the order of the
DataAdapter.Update() would be dependent on the actual changes done in the
DataSet (in order to not get exceptions regarding relationship constraints).
In some cases, for example for self-referring tables, there is no way to
update multiple circular chages using one single DataAdapter.Update() call
(because the data is updated sequentially by the adapter, and the order of
the changes is not the order of change occurence, but in the primary key
order - and in some cases, entities updated first would refer entities that
would be updated later and the database would complain after the first update
that the referencial integrity is lost).
Ok. Now back to my point. The idea above works in theory, and it also works
in practice but only for changes of these DataRowAction type: Change and
Delete. It doesn't work for Add. Specifically, when a new row is added in a
table in the DataSet, the new row is not got by the GetChanges() call in the
RowChanged event handler, although modified rows and deleted rows are. As I
read on other blogs and posts, it seems that this is a bug in the DataSet of
ADO .NET 1.1, and seems to be solved in .NET 2.0 (tested it myself).
However, because I need to stick with 1.1 for this application, what are
your suggestions regarding this issue? Specifically, how to get the Add
changes also? I even tried to add them manually, in case that e.RowAction ==
Add, by creating a new DataSet using myDataSet.clone() and adding the e.Row
in the table with the same name of the DataSet (also needed to set
EnforceConstraints to false for the changes to be able to do that) instead of
GetChanges() call, but I feel that this workaround is not my best choice.
Also, it's out of discussion to create a new thread that would be started by
the RowChanged event hander (to allow .NET add the row in the meantime, and
to be gettable with GetChanges() after that), and to do the GetChanges()
there - because of the problem that I cannot lock the DataSet from the event
hanlder function and release it in another thread... And what if .NET doesn't
add the row until the thread gets to the GetChanges() call...
Waiting for the Commit DataRowAction is also unapropriate because the
threads that add rows to the DataSet's tables do not call AcceptChanges() for
each Add operation they make...
I hope that there is another good and nice workaround for this problem -
maybe somebody else found it before me and can share the knowledge. Or at
least, advise me what other approach to take in order to reach my goals for
this application.
If in the meantime I will find any good workaround myself, I will post it
here.
Thank you again, in advance.
I have a pretty difficult question about a hard-to-explain issue (I hope my
English would be good enough to make you understand). The environment beside
the problem itself may also be important, so I'm gonna explain a little the
whole idea and then go back to the issue and my question. Thanks in advance
for your time.
I am developing a .NET 1.1-based application that uses a main central
DataSet instance as a local cache storage for the current user-based slice of
data stored in an SQL Server database. The application consists of several
threads that may access the DataSet either to retreive data or for updating
data.
A special thread in the application is set to listen to all DataSet's
tables' RowChanged and RowDeleted events through a single event handler that
does something like this:
public void RowChanged(object sender, DataRowEventArgs e)
{
lock (myDataSet)
{
DataSet changes = myDataSet.GetChanges();
if (changes != null)
{
myDataSet.AcceptChanges();
//... Store changes in a changes queue, for later use in background
synchronization to the SQL Server database (using multiple
DataAdapter.Update() commands, one for each DataTable in the DataSet)
}
}
}
All the other threads that use the DataSet are using a lock(myDataSet) block
in order to maintain thread safety of the operations.
The idea here is to get all the changes that are done to the local DataSet
in a one-by-one way, so that I can update them back to the SQL Server (like a
"replication" synchronization) in a background thread and do not affect the
user's experience in that process.
Some would argue about the comment above that it won't be necessary to get
the changes one-by-one as I could from time to time execute a
myDataSet.GetChanges() in the background thread itself and update all the
changes back to the database at once -- however, this is not true because I
have circular relationships between the database tables, and the order of the
DataAdapter.Update() would be dependent on the actual changes done in the
DataSet (in order to not get exceptions regarding relationship constraints).
In some cases, for example for self-referring tables, there is no way to
update multiple circular chages using one single DataAdapter.Update() call
(because the data is updated sequentially by the adapter, and the order of
the changes is not the order of change occurence, but in the primary key
order - and in some cases, entities updated first would refer entities that
would be updated later and the database would complain after the first update
that the referencial integrity is lost).
Ok. Now back to my point. The idea above works in theory, and it also works
in practice but only for changes of these DataRowAction type: Change and
Delete. It doesn't work for Add. Specifically, when a new row is added in a
table in the DataSet, the new row is not got by the GetChanges() call in the
RowChanged event handler, although modified rows and deleted rows are. As I
read on other blogs and posts, it seems that this is a bug in the DataSet of
ADO .NET 1.1, and seems to be solved in .NET 2.0 (tested it myself).
However, because I need to stick with 1.1 for this application, what are
your suggestions regarding this issue? Specifically, how to get the Add
changes also? I even tried to add them manually, in case that e.RowAction ==
Add, by creating a new DataSet using myDataSet.clone() and adding the e.Row
in the table with the same name of the DataSet (also needed to set
EnforceConstraints to false for the changes to be able to do that) instead of
GetChanges() call, but I feel that this workaround is not my best choice.
Also, it's out of discussion to create a new thread that would be started by
the RowChanged event hander (to allow .NET add the row in the meantime, and
to be gettable with GetChanges() after that), and to do the GetChanges()
there - because of the problem that I cannot lock the DataSet from the event
hanlder function and release it in another thread... And what if .NET doesn't
add the row until the thread gets to the GetChanges() call...
Waiting for the Commit DataRowAction is also unapropriate because the
threads that add rows to the DataSet's tables do not call AcceptChanges() for
each Add operation they make...
I hope that there is another good and nice workaround for this problem -
maybe somebody else found it before me and can share the knowledge. Or at
least, advise me what other approach to take in order to reach my goals for
this application.
If in the meantime I will find any good workaround myself, I will post it
here.
Thank you again, in advance.