ironwill96
asked on
ADO.Net - Cannot get DataSet to Update into Database
OK,
Needless to say i'm quite frustrated with ADO.net compared to ADO or even good old DAO from my VB 6 days. I am trying in vain to get changes i've made to a DataRow to populate back to the database No matter what I do it doesnt work or I get errors about not having a properly formatted Update command. Perhaps I really just don't understand how ADO.Net is supposed to work. I thought you have this disconnected dataset that you make changes to in-memory and then when you call someDataSet.AcceptChanges( ); it would populate all your changes back to the database for you, perhaps optionally passing just the source table you want to repopulate. However, that does not seem to be the case. I've seen all kinds of conflicting answers on EE as well as on PSC and other websites about how to best do this and whether to just use ADO instead of ADO.Net.
So, my first question: Is ADO.Net a REPLACEMENT for ADO, or IN ADDITION TO ADO? Are there speed advantages to using ADO.net vs. ADO when you don't really care about disconnected datasets so much? ADO.Net is such a radically different way of thinking i'm almost ready to take a performance hit and revert to ADO style recordsets b/c it makes sense and "works" correctly the way I intend every time.
My second question, my code is shown below for opening the database and then doing updates on one row inside it. Please let me know what i'm doing wrong so that it doesnt work.
/*
* Open a connection to the database
*/
private void openDatabase()
{
this.dbConnect = new OleDbConnection();
this.dbConnect.ConnectionS tring = @"Provider=Microsoft.Jet.O LEDB.4.0;" +
@"Data source= .\main.mdb";
try
{
//attempt to open the database
//for now just leave this connection open
this.dbConnect.Open();
}
catch (Exception ex)
{
string errmsg = "Error Message: " + ex.Message;
}
}
private void btnUpdateCompany_Click(obj ect sender, EventArgs e)
{
//update all of the relevant information after verifying that they have all the proper
//fields filled out
//removed all the verify code for EE as it just takes up space and works fine
OleDbDataAdapter daOurAdapter;
DataSet dsResults;
//do a search
this.mstrSQL = "SELECT * FROM Customers WHERE CustomerID = " + this.CustomerID;
this.openDatabase();
try
{
//create the adapter with the SQL string and the ADO style connection (dbConnect is initialized in this.openDatabase() from above)
daOurAdapter = new OleDbDataAdapter(this.mstr SQL, this.dbConnect);
//make our dataset object an actual dataset
dsResults = new DataSet();
//now fill our dataset object with data (if any)
daOurAdapter.Fill(dsResult s, "Customers");
//we now have a DataSet object that contains any results that have been returned by our query
//create a DataTable object representing the table returned
DataTable dtCustomers = dsResults.Tables["Customer s"];
//check to see if any data is actually contained in the results
if (dtCustomers.Rows.Count > 0)
{
DataRow drCustomerResults = dtCustomers.Rows[0];
drCustomerResults.BeginEdi t();
//update all the data from the form inputs now
drCustomerResults["Company Name"] = txtCompanyName.Text;
drCustomerResults["Special Notes"] = txtSpecialNotes.Text;
drCustomerResults["Usernam e"] = txtUsername.Text;
drCustomerResults["Passwor d"] = txtPassword.Text;
drCustomerResults["EmailAd dress"] = txtEmailAddress.Text;
drCustomerResults["FirstNa me"] = txtFirstName.Text;
drCustomerResults["LastNam e"] = txtLastName.Text;
drCustomerResults["PhoneNu mber"] = txtPhoneNumber.Text;
drCustomerResults["FaxNumb er"] = txtFaxNumber.Text;
drCustomerResults["Country "] = txtCountry.Text;
drCustomerResults["Billing Address"] = txtAddress.Text;
drCustomerResults["BillCit y"] = txtCity.Text;
drCustomerResults["BillSta te"] = cboState.Text;
drCustomerResults["BillZip Code"] = txtZipCode.Text;
drCustomerResults["CreditC ardType"] = cboCreditCard.Text;
drCustomerResults["CreditC ardNumber" ] = txtCreditCardNumber.Text;
drCustomerResults["ShipAdd ress"] = txtShipAddress.Text;
drCustomerResults["ShipCit y"] = txtShipCity.Text;
drCustomerResults["ShipSta te"] = cboShipState.Text;
drCustomerResults["Preferr edShipping "] = cboPreferredShipping.Selec tedIndex;
drCustomerResults["Shippin gNumber"] = txtShippingNumber.Text;
drCustomerResults["ShipZip "] = txtShipZipCode.Text;
drCustomerResults["ShipCou ntry"] = txtShipCountry.Text;
if (txtShipAddress.Enabled == false)
drCustomerResults["Shippin gSame"] = 1;
else
drCustomerResults["Shippin gSame"] = 0;
//push all changes to the database
drCustomerResults.EndEdit( );
// drCustomerResults.AcceptCh anges();
DataSet dsChanges = dsResults.GetChanges();
if (dsChanges != null)
{
if (!dsChanges.HasErrors)
{
dsResults.Merge(dsChanges) ;
//very important to put the table name
//ERROR OCCURS HERE..
daOurAdapter.Update(dsResu lts, "Customers");
dsResults.AcceptChanges();
}
}
//daOurAdapter.Update(dsCh anges, "Customers");
//I"D PREFER TO BE ABLE TO JUST MAKE THE CALL BELOW AND HAVE IT ALL UPDATE..WHY DOESNT THIS WORK?
//dsResults.AcceptChanges( );
}
}
catch (Exception ex)
{
string strMsg = "Error Message = " + ex.Message;
}
this.closeDatabase();
this.Close();
}
I stuck in some comments about my issue in the code itself. I really really hope that there is something stupid i'm overlooking to get ADO.Net to update the database without having to create temp Datasets to merge changes into or doing .insertCommand string type stuff to form the update SQL into the Adapter. That all seems rather silly to me and I don't see the point, especially if I don't particularly need reusability on this form, there is no real reason to waste all the time writing re-usable SQL commands!
Thanks in advance,
Nathan
Needless to say i'm quite frustrated with ADO.net compared to ADO or even good old DAO from my VB 6 days. I am trying in vain to get changes i've made to a DataRow to populate back to the database No matter what I do it doesnt work or I get errors about not having a properly formatted Update command. Perhaps I really just don't understand how ADO.Net is supposed to work. I thought you have this disconnected dataset that you make changes to in-memory and then when you call someDataSet.AcceptChanges(
So, my first question: Is ADO.Net a REPLACEMENT for ADO, or IN ADDITION TO ADO? Are there speed advantages to using ADO.net vs. ADO when you don't really care about disconnected datasets so much? ADO.Net is such a radically different way of thinking i'm almost ready to take a performance hit and revert to ADO style recordsets b/c it makes sense and "works" correctly the way I intend every time.
My second question, my code is shown below for opening the database and then doing updates on one row inside it. Please let me know what i'm doing wrong so that it doesnt work.
/*
* Open a connection to the database
*/
private void openDatabase()
{
this.dbConnect = new OleDbConnection();
this.dbConnect.ConnectionS
@"Data source= .\main.mdb";
try
{
//attempt to open the database
//for now just leave this connection open
this.dbConnect.Open();
}
catch (Exception ex)
{
string errmsg = "Error Message: " + ex.Message;
}
}
private void btnUpdateCompany_Click(obj
{
//update all of the relevant information after verifying that they have all the proper
//fields filled out
//removed all the verify code for EE as it just takes up space and works fine
OleDbDataAdapter daOurAdapter;
DataSet dsResults;
//do a search
this.mstrSQL = "SELECT * FROM Customers WHERE CustomerID = " + this.CustomerID;
this.openDatabase();
try
{
//create the adapter with the SQL string and the ADO style connection (dbConnect is initialized in this.openDatabase() from above)
daOurAdapter = new OleDbDataAdapter(this.mstr
//make our dataset object an actual dataset
dsResults = new DataSet();
//now fill our dataset object with data (if any)
daOurAdapter.Fill(dsResult
//we now have a DataSet object that contains any results that have been returned by our query
//create a DataTable object representing the table returned
DataTable dtCustomers = dsResults.Tables["Customer
//check to see if any data is actually contained in the results
if (dtCustomers.Rows.Count > 0)
{
DataRow drCustomerResults = dtCustomers.Rows[0];
drCustomerResults.BeginEdi
//update all the data from the form inputs now
drCustomerResults["Company
drCustomerResults["Special
drCustomerResults["Usernam
drCustomerResults["Passwor
drCustomerResults["EmailAd
drCustomerResults["FirstNa
drCustomerResults["LastNam
drCustomerResults["PhoneNu
drCustomerResults["FaxNumb
drCustomerResults["Country
drCustomerResults["Billing
drCustomerResults["BillCit
drCustomerResults["BillSta
drCustomerResults["BillZip
drCustomerResults["CreditC
drCustomerResults["CreditC
drCustomerResults["ShipAdd
drCustomerResults["ShipCit
drCustomerResults["ShipSta
drCustomerResults["Preferr
drCustomerResults["Shippin
drCustomerResults["ShipZip
drCustomerResults["ShipCou
if (txtShipAddress.Enabled == false)
drCustomerResults["Shippin
else
drCustomerResults["Shippin
//push all changes to the database
drCustomerResults.EndEdit(
// drCustomerResults.AcceptCh
DataSet dsChanges = dsResults.GetChanges();
if (dsChanges != null)
{
if (!dsChanges.HasErrors)
{
dsResults.Merge(dsChanges)
//very important to put the table name
//ERROR OCCURS HERE..
daOurAdapter.Update(dsResu
dsResults.AcceptChanges();
}
}
//daOurAdapter.Update(dsCh
//I"D PREFER TO BE ABLE TO JUST MAKE THE CALL BELOW AND HAVE IT ALL UPDATE..WHY DOESNT THIS WORK?
//dsResults.AcceptChanges(
}
}
catch (Exception ex)
{
string strMsg = "Error Message = " + ex.Message;
}
this.closeDatabase();
this.Close();
}
I stuck in some comments about my issue in the code itself. I really really hope that there is something stupid i'm overlooking to get ADO.Net to update the database without having to create temp Datasets to merge changes into or doing .insertCommand string type stuff to form the update SQL into the Adapter. That all seems rather silly to me and I don't see the point, especially if I don't particularly need reusability on this form, there is no real reason to waste all the time writing re-usable SQL commands!
Thanks in advance,
Nathan
Hello
In addition to David's comment if you just want to insert a row in the access table do the following:
if you are using .net 1.1 use OleDbCommand and execute a sql query to insert your data.
if you are using .net 2 open a dataset file and drag your access table from server explorer to the dataset. In .net 2 tables in dataset can have a connection to the datasource. Know build your solution and go to your form. drag your new dataset from toolbox to the form and drag the table (tableadapter) from the toolbox to the form.
now you can easily insert rows to the datasource by calling the Insert method of tableadapter.
hope you success
Heidar
In addition to David's comment if you just want to insert a row in the access table do the following:
if you are using .net 1.1 use OleDbCommand and execute a sql query to insert your data.
if you are using .net 2 open a dataset file and drag your access table from server explorer to the dataset. In .net 2 tables in dataset can have a connection to the datasource. Know build your solution and go to your form. drag your new dataset from toolbox to the form and drag the table (tableadapter) from the toolbox to the form.
now you can easily insert rows to the datasource by calling the Insert method of tableadapter.
hope you success
Heidar
ASKER
Good information from both of you but i'm looking for some actual code examples of how to do a successful update of a record after the code I have up there makes the changes (assuming that i'm doing the changes correctly of course).
Thanks,
Nathan
Thanks,
Nathan
Are you asking for a way to update a record, or write the changes back to the database using the data adapter?
Bob
Bob
Hello Dear
This is so easy with typed Dataset
see these links
http://www.informit.com/articles/article.asp?p=30103
http://www.c-sharpcorner.com/Code/2004/Jan/TypedDataSets.asp
http://www.15seconds.com/issue/031223.htm
http://www.c-sharpcorner.com/Code/2004/Jan/TypedDataSets.asp
This is so easy with typed Dataset
see these links
http://www.informit.com/articles/article.asp?p=30103
http://www.c-sharpcorner.com/Code/2004/Jan/TypedDataSets.asp
http://www.15seconds.com/issue/031223.htm
http://www.c-sharpcorner.com/Code/2004/Jan/TypedDataSets.asp
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
You are missing the commandbuilder object. In ADO.net you have to tell it what insert and update command to use to update the tables, to make it easier MSFT give you the command builder object. After you declare your data adapter, declare a commandbuilder object. That's it, pretty simple after that.
//create the adapter with the SQL string and the ADO style connection (dbConnect is initialized in this.openDatabase() from above)
daOurAdapter = new OleDbDataAdapter(this.mstr SQL, this.dbConnect);
OleDbCommandBuilder cmdOurBuilder = new OleDbComandBuilder(daOurAd apter);
//create the adapter with the SQL string and the ADO style connection (dbConnect is initialized in this.openDatabase() from above)
daOurAdapter = new OleDbDataAdapter(this.mstr
OleDbCommandBuilder cmdOurBuilder = new OleDbComandBuilder(daOurAd
Hello Nathan,
are you using .net 1 or 2?
Heidar
are you using .net 1 or 2?
Heidar
ASKER
I'm using .Net 2.0.
Thanks for all the help everyone, I am trying out your suggestions now.
Nathan
Thanks for all the help everyone, I am trying out your suggestions now.
Nathan
ASKER
Thanks sohilm but AnyoneIs posted his example (with the also correct creation of the Command Builder object) before you. I appreciate all the help. I can't believe it was something so simple (as usual). A++ help AnyoneIs, now I can quit trying to figure out ways to Murder ADO.Net on my computer!
Thanks again,
Nathan
Thanks again,
Nathan
When you call DataSet.AcceptChanges(), you are saying, take all of the inserts, updates, and deletes you have been keeping track of and make them the current data in the DataSet - that's all yopu are saying! That operation has no connection with the real database. Only the Adapter.Update() will persist your changes.
Comments about specific protions of your code/comments:
>> //now fill our dataset object with data (if any)
>> daOurAdapter.Fill(dsResult
Actually, the line will create or emptyandrefill a DataTable object called "Customers" in the dataset (actual specific behavior depends on prexistance of table and options set in the DataAdapter - and on whether or not multiple result sets are returned by the query.)
>> //create a DataTable object representing the table returned
>> DataTable dtCustomers = dsResults.Tables["Customer
Why? Why not just update the records directly in the DataSet (OK, in the DataTable "Customers" in the DataSet). The DataSet keeps multiple versions of the data - original, current, and proposed. There is no need to make a copy.
I probably missed some things - e.g. why specifically you are getting the error - I suspect that the tablename in dsChanges is "Table1" - all it is getting is a rowset when you call GetChanges, so it would not know that the table was called.
If you want to do things this way, I would recommend "Microsoft® ADO.NET (Core Reference) " by David Sceppa. If you want a MUCH better way, I would strongly recommend "Data Binding with Windows Forms 2.0 : Programming Smart Client Data Applications with .NET (Microsoft Net Development Series) (Paperback) " by Brian Noyes.
David