Updating a Dataset: How the Adapter works inside ?

G

Guest

Hello,

I am currently writing a DAL. When calling the DataAdapter.Update function
for a Dataset, does the DataAdapter calls DataSet.GetChanges() internally
before looping through rows? Or should my DAL be responsible to call
GetChanges before updating?

Thank you

(I am talking about a single table dataset, disregarding the cases where the
GetChanges must be called for multiple tables datasets)
 
M

Marina

It will only update rows with changes, if that is what you are asking. You
may want to call GetChanges first, if for example you have a web service
updating the data, and you only want to send the rows with changes for
performance reasons.
 
G

Guest

Thank you Marina but not quite what I was asking.

I know the DataAdapter.Update only updates the rows with changes, what I am
wondering is if the it loops through all the rows it receives or only loops
thorugh the rows with changes.

Thansk anyway
 
J

J L

You may want to check out this article...a good example of creating
DAL's IMHO.

http://msdn.microsoft.com/msdnmag/issues/02/02/data/default.aspx

He creates a dataset of only the changes before doing the update to
reduce network traffic...according to the article. I am new to all of
this and struggling with designing my own DAL process. Coming from DAO
and recordsets, it is a stretch of the imagination...so many ways to
do things.

John
 
M

Marina

Does that really matter?

To get a list of all the rows with changes, it has to first loop through all
the rows anyway to find all the ones with changes. So it all amounts to the
same amt of work, whether you loop through, get all the changes, and hand it
off to the adapter, or whether it does it on its own.

I supposed they could have a more complicated scheme of adding rows to
various collections to keep track of added, updated, etc, rows. You can find
a decompiler and look at the internal code - if you really care that much.
But does it really matter?
 
G

Guest

Marina,
IMHO it does matter. For instance, if you receive a Dataset with thousands
of records where only a dozen need updating.

Keeping the discussion in context, I was talking exclusively about DAL
programming.
It is obvious that passing thousands of records to the Data Layer when only
a few records need update is poor Business Layer programming, specially if
the Data Layer is a separate Tier.

As you said, the DataAdapter might loop the dataset anyway, but also, as you
said, it is likely the DataSet has an optimized internal implementation.

I have posted another topic "Updating a Dataset 2nd Part" where I really
explain why I made this question in the first place. It has to do with
keeping track of the success updates per DataRow, a neat feature, easy to
implement.

Such implementation is much easier if the DataSet passed to the
DataAdapter.Update method is the same DataSet received from the Business
Layer. However when calling the GetChanges method, we are creating a copy,
lossing the update success tracking per Row:


myDataAdapter.Update(myDataSet); //keeping track of update errors

myDataAdapter.Update(myDataSet.GetChanges()); //cannot keep track of update
errors

I don't want to extend myself in this post ... please check the other one:
"Updating a DataSet 2nd Part"

Thanks for the answers :)
 
M

Marina

Yes, the dataset can be optimized to not loop. But then odds are, GetChanges
would be optimized in the same way. So it really amounts to the same thing.
Who knows - you would have to look.

Wouldn't the fastest and easiest way to answer this question if you really
care about it, is to run a test to see which way is faster?
 
C

Cor Ligthert

Abelardo,

You make me curious.
myDataAdapter.Update(myDataSet.GetChanges()); //cannot keep track of
update
errors
Why not it has all the information from the original dataset and it is only
a copy.

The original datarow when there is an error can easily be found in the
original dataset by using a datarowcollection find in my opinion.

Therefore enlighten me what I miss?

Cor
 
G

Guest

Why not it has all the information from the original dataset and it is only

The short answer: Because it is a copy, GetChanges generates a subset of the
rows in an entirely different DataSet. The DataRow.RowError information is
there, but in the copy, not in the original DataSet.


For the long answer I am copying this from my other post:

When updating a SINGEL TABLE Dataset I keep track of the rows that were
succesfully updated , but it does not look the slickest solution when working
with MULTIPLE RELATED TABLES.

Here is what I do (quite simple):
1. Registering my adapter to handle the RowUpdated event:
myDataAdapter.RowUpdated +=new
OleDbRowUpdatedEventHandler(myDataAdapter_RowUpdated);

2. Handling the RowUpdated event to store the error message and skip the
AcceptChanges call:
private static void myDataAdapter_RowUpdated(object sender,
OleDbRowUpdatedEventArgs e)
{
if (e.Status == UpdateStatus.ErrorsOccurred)
{
e.Row.RowError = e.Errors.Message;
e.Status = UpdateStatus.SkipCurrentRow;
}
}

3. And last, simply updating the data set:
myDataAdapter.Update(myDataSet);

Since "SkipCurrentRow" will skip the call to DataRow.AcceptChanges(), the
resulting dataset (after it has been updated) will keep the RowState for
those rows where an error ocurred, the rest of the rows will have a
"Unchanged" state. This is all great!!!

Now, in a multiple tables datasets with relationships among the tables, the
DataSet.GetChanges() method is a MUST to control the order in which updates
are
performed.

The question is:

--- How do I get the same behaviour of keeping track of the rows that were
sucessfully updated ? Since when using DataSet.GetChanges(), I am sending
copies of the DataSet to the DataAdapter.Update (instead of passign the
DataSet itself), then the RowState and RowError are not stored in my
original
DataSet. ---

My solution so far involves merging the copies of the DataSet with the
original DataSet. This works, but to a certain extend:

DataSet originalDS;

DataSet deletedDS = originalDS.GetChanges(DataRowState.Deleted);
DataSet modifiedDS = originalDS.GetChanges(DataRowState.Added
|DataRowState.Modified);

originalDS.AcceptChanges(); //reseting the row states

myDataAdapter2.Update(deletedDS, "Table2");
myDataAdapter1.Update(deletedDS, "Table1");

originalDS.Merge(deletedDS); //getting the Errors copied into the original DS

myDataAdapter1.Update(modifiedDS, "Table1");
myDataAdapter2.Update(modifiedDS, "Table2");

originalDS.Merge(modifiedDS); //getting the Errors copied into the original
DS

At this point my DataSet has the RowError messages, BUT the RowStates for
the Rows with Error are all set Modified, instead of Added, Deleted or
Modified (This is the effect of performing the DataSet.Merge.) Compared to
the single table DataSet, this solution is a pain, and the only way I see
around it would be looping right after each Merge, yet worse, updating
Modified and Added rows
separately!!!


Thanks for your opinions .... and for reading this far :)
 
C

Cor Ligthert

The short answer: Because it is a copy, GetChanges generates a subset of
the
rows in an entirely different DataSet. The DataRow.RowError information is
there, but in the copy, not in the original DataSet.
However they have the same primary keys, I really not see the point. when an
error is catched and I know the row, than I know in my opinion the original.
Tell me what I miss?

Cor
 
G

Guest

Hi Cor,
when an error is catched and I know the row, than I know in my opinion the
original.

Well put, and it is true. But remember I am talking about building a DAL.
The code exposed in these samples is not intended for a small application
where you can find Data Access Logic in the Forms, but for an N-Layer
architecture where

The programmer who will use the Data Access Layer Components, and send the
original DataSet will only see something like this:

CustomersDALC.Update(myCustomersDataSet);

This "myCustomersDataSet" is my 'original' dataset within the DALC method:

public void Update(DataSet myDataSet)
{
.... code preparing the DataAdapter
myDataAdapter.Update(myDataSet); // cool, I am using the original
}

what if it is a multiple table Dataset with relationships:

public void Update(DataSet myDataSet)
{
.... code preparing the DataAdapterS
myDataAdapter1.Update(myDataSet.GetChanges(deleted), "Table1");
myDataAdapter2.Update(myDataSet.GetChanges(deleted), "Table2");

... the rest of the code for modified and added rows

... now myDataSet does not reflect the RowErrors.
}

Cor, while it is true the RowErrors are available to me within the
customersDALC.Update method, what I really need to do is make them available
to the caller (Business Layer in most cases)

As I posted before, the process of using Merge is kind of messy .... I am
hoping for a cleaner option.

Thanks
 
C

Cor Ligthert

Abelardo,

I get the idea that we are reaching the end.
This "myCustomersDataSet" is my 'original' dataset within the DALC method:
This is a "reference" to your original dataset (assuming you do it by value)
and therefore completly usable. It is not a passing of a dataset itself. It
is completly the refrence to the original dataset and therefore you can do
what you want with it.

Cor
 
G

Guest

Hi Cor,
This is a "reference" to your original dataset (assuming you do it by value)
and therefore completly usable. It is not a passing of a dataset itself. It
is completly the refrence to the original dataset and therefore you can do
what you want with it.

Indeed. We do not disagree on this. I can do what I want with this DataSet,
the issue was HOW to do it. I do not particulary like the way I am doing it
now (using the DataSet.Merge.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top