Re: DataSet.GetChanges() in RowChanged(DataRowAction.Add)



Sorin:

The following recommendation is based solely on what I understand to be the
nature of your program and not generall what I'd advise. The first thing
that comes to mind is using Sql Server CE or Sql Mobile , or Oracle Lite and
just use it as the back end - then do the synchronization there. There are
some killer benefits in the 2.0 framework to this approach but as you
mentioned, you want to stick with 1.1. What you get by doing this is a
trusted, tested, performant and flexible way to solve your problem.
Moreoever, if the way synchronization needs to be handled changes in the
future, changing the synchronization model is pretty simple and can be done
almost transparently. If you roll your own (which may for reasons I'm not
aware of yet not be feasible) you are essentially re-creating a very very
complex wheel. By using Sql CE or Sql Mobile etc, you also have tremendous
advantages in terms of security and conflict resolution that would be next
to impossible (and definitely something undesirable) to recreate).

I'm not sure if it's possible, but from the sounds of it, you can use other
events, like Button clicks or other UI Cues to do the same thing you are
trying to accomplish with the datatable events. Would I normally suggest
using the UI instead of the objects themselves. NO. But your case is
specific and depending on what you need, it may be a viable solution.

Finally, and remember, I only say this b/c of the specific nature of your
app, if none of the above will work, is it possible that you can not use a
DataSet/DataTable as your primary object for storage? For instance, if you
don't need Sorting, Selecting, Computing etc and you're just using the
objects as data stores, then you could just roll your own collection of
collections and add those events in yourself. Normally (as you can tell
from my first suggestion), I'd not recommend rolling your own object when
there's already something peer reviewed and widely used (like DataSets) that
are already coded. But, in cases where you don't need the specific
functionality of a datatable/dataview/dataset, and you're just using them to
store data, then it may make sense. Remember that you can implement the
same interfaces for instances, so that you can still bind to them or
effectively make your new object have all the features that users would
normally want (I know, this sounds contradictory but what I mean is that you
can implement the thing partially) recreating only the features that the
application needs.

I know i covered vastly different approaches here and I may well have not
understood your requirements correctly - if that's the case, please let me
know and I'll take a stab at it again,

Thanks,

Bill





"Sorin Dolha" <sdolha@xxxxxxxxxxxxxxxx> wrote in message
news:162C393C-A419-4FA2-B38B-5EC57D06CA82@xxxxxxxxxxxxxxxx
> 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.
>
> --
> Sorin Dolha, DlhSoft
> MCAD, MCSD .NET


.