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

Posted on 2004-10-25
Last Modified: 2008-02-01
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.
Question by:grokuk
    LVL 1

    Accepted Solution

    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.


    Author Comment

    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 :)
    LVL 1

    Expert Comment


    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.

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone. Privacy Policy Terms of Use

    Featured Post

    Anonabox PRO Tor & VPN Router

    PRO is the most advanced way to fortify your privacy and online anonymity by layering the Tor network with VPN services. Use both together or separately, and without needing to download software onto your devices.

    The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
    In Easy String Encryption Using CryptoAPI in C++ ( I described how to encrypt text and recommended that the encrypted text be stored as a series of hexadecimal digits -- because cyphertext may…
    With the advent of Windows 10, Microsoft is pushing a Get Windows 10 icon into the notification area (system tray) of qualifying computers. There are many reasons for wanting to remove this icon. This two-part Experts Exchange video Micro Tutorial s…
    To add imagery to an HTML email signature, you have two options available to you. You can either add a logo/image by embedding it directly into the signature or hosting it externally and linking to it. The vast majority of email clients display l…

    877 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    20 Experts available now in Live!

    Get 1:1 Help Now