DataSet Fill from SQL Server then Update to OleDb (Access) in MC++

I am trying to retrieve some data from a disconnected SQl Server database via a DataSet and then Insert the contents of this dataSet into a local Access database.

The first part is working just fine. I'm using the following code:

String *ConnectionString = S"Data;Initial Catalog=MyForums;User Id=user;Password=fake;";
SqlConnection * conSql = new SqlConnection(ConnectionString);                        
SqlCommand *sqlSelect = new SqlCommand();
sqlSelect->CommandText = String::Concat(S"SELECT * FROM Posts WHERE ForumID=",
      ForumID.ToString(), S" AND Sent>'", Since.ToString(), S"' ORDER BY Sent");
sqlSelect->Connection = conSql;

SqlDataAdapter *dataAdapter = new SqlDataAdapter();
dataAdapter->SelectCommand = sqlSelect;

DataSet *ds = new DataSet();

The DataSet Fills up with the correct data. So next I create an OleDb DataAdapter to store in the local Access database like so:

OleDbConnection *oleConnection = new OleDbConnection(S"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=.\\hsf.mdb");

OleDbCommand *oleInsert = new OleDbCommand();
oleInsert->CommandText = S"INSERT INTO Posts VALUES (?,?,?,?)");
oleInsert->Connection = oleConnection;
oleInsert->Parameters->Add(new OleDbParameter(S"@PostID", OleDbType::BigInt, 8, S"PostID"));
oleInsert->Parameters->Add(new OleDbParameter(S"@ForumID", OleDbType::BigInt, 8, S"ForumID"));
oleInsert->Parameters->Add(new OleDbParameter(S"@ThreadID", OleDbType::BigInt, 8, S"ThreadID"));
oleInsert->Parameters->Add(new OleDbParameter(S"@ReplyToID", OleDbType::BigInt, 8, S"ReplyToID"));

OleDbDataAdapter *accessAdapter = new OleDbDataAdapter();
accessAdapter->InsertCommand = oleInsert;

When this executes, nothing happens. No error is generated but the Update method returns 0 and nothing is written to the database.

I have found that if I manually create a new DataSet and write in the appropriate columns and row values, that will Update just fine. So I think the problem lies within the DataSet itself and not OleDb code.

Can anyone suggest what is wrong, or am I going about this in the wrong way enitrely? Thanks.
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Hi grokuk,

A dataset has a number of versions of each data row. These are described by the System::Data::DataRowVersion enumeration. The row versions are: Current, Default, Original, Proposed. In effect, it is like having four distinct copies of each datarow.

When you modify a row, the original version stays the same, but the proposed version shows the changes you have made. When you wish to update the database with the changes, the Update method will look to see if anything has changed in the dataset since it was last declared current. It determines if there are changes by looking at the proposed version of each row. When it sees the changes, it calls the appropriate command: UpdateCommand if the change requires an update statement; InsertCommand if the change requires a new row in the database; and the DeleteCommand if your changes deletes a row in the dataset and database.

This is half the story. The other half is that your Update, Delete, and Insert commands must use the parameters, and you must specify which datarow version the parameter is filled from.

I believe this is the problem with your example above. The parameters you have specified for the oleInsert command do not specify the row version to be filled from. Since your dataset does not appear to have any changes, nothing is going to be updated. If there were changes to reflect into your Access database, which version of the dataset's rows would the parameters fill from?

For your case, your oleInsert command might need to read like this example:

oleInsert->Parameters->Add(new OleDbParameter(S"@PostID", OleDbType::BigInt, 8, S"PostID", System::Data::DataRowVersion::Original);

After you have completed the Update, if there have been any changes to the dataset, you need to "Accept" the changes so that a repeated call to Update does not try to send the changes again. This is done with the AcceptChanges method which can be called on the dataset object or the table object.

Hope that helps.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
grokukAuthor Commented:
Thanks javanic,

Your comments have helped me to see the problem. I can't actually add the DataRowVersion::Original parameter to the new OleDbParameter constructor as there isn't an overload that supports this combination.

However, I found that by setting:

dataAdapter->AcceptChangesDuringFill = false;

Just before the original Fill stops an AcceptChanges which is called automatically, thus leading to the version problem you've described. Adding this line fixes everything, and the OleDb part of the code now works without alteration.

I wouldn't have found this without your excellent comments. So, many thanks :)

I should have checked the overloads before just typing it in. There is an overload that uses the datarow version enumeration; it looks like this:
public: OleDbParameter(
   String* parameterName,
   OleDbType dbType,
   int size,
   ParameterDirection direction,
   bool isNullable,
   unsigned char precision,
   unsigned char scale,
   String* srcColumn,
   DataRowVersion srcVersion,
   Object* value
I believe the reason your AcceptChangesDuringFill is working is because in effect you have made your entire dataset to look like it is modified (as though the fill were actually inserting new rows into your dataset). If you only want to fill the dataset from the offline SQL database, and then ship the data to Access database, this should be ok. But if you want to use the dataset for anything (which is what makes the dataset so powerful), you may find that you can't keep track of changes properly.

Glad to have helped.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual C++.NET

From novice to tech pro — start learning today.