Upserting a DataTable via a proc call C# - c#

I have the following lines of code that call a proc and return the results of the proc call and place them into a DataTable
DataTable dt = new DataTable();
SqlDataAdapter data = new SqlDataAdapter();
_repo.ExecuteSprocPopulateDataTable(command, null, dt);
When I debug my code, my datatable is populated with the results as expected but I'm stuck on passing the data back up in to my database via another proc.
I've looked and seen some stuff about SqlDataAdapters and tried the following line:
data.Update(dt.DataSet, _command);
But when I do, it tells me that Value can not be null which relates to my dataset.
Can someone advise the best way for me to upsert my data via a proc call?

Not quite sure what that _command there is, but with SqlDataAdapters, updates typically go like this:
try
{
using (SqlCommandBuilder cb = new SqlCommandBuilder(data))
{
data.InsertCommand = cb.GetInsertCommand();
data.UpdateCommand = cb.GetUpdateCommand();
data.DeleteCommand = cb.GetDeleteCommand();
data.Update(dt);
}
}
catch (Exception ex)
{
// handle errors
}

Related

C# Not updating modified dataset to SQL Server table

I've been working on a small project and came to an issue with a SQL Server database. The SQL Server database works fine when connecting and reading from it. There are no issues when it comes to the variables, they all update fine.
However, the database itself does not update at all. I believe it is the da.Update that is going wrong, but I've never worked with SQL before so I can't find what is wrong with it.
What it should do:
Read data from the SQL Server table
Put it in a DataTable
Take changes from a list and put them into the DataTable
Add the changes to the database
What it does do:
Reads the data from the SQL Server table
Puts it in a DataTable
Takes changes from a list and puts them into the DataTable
Doesn't update the database, but does not fail the try and catch
Code:
public void PushToDatabase()
{
// Get update from list
PropertiesList[0] = Name;
PropertiesList[1] = Token;
PropertiesList[2] = ClientID;
PropertiesList[3] = ClientInfo;
PropertiesList[4] = Owner;
PropertiesList[5] = OtherID;
PropertiesList[6] = Prefix;
PropertiesList[7] = ApiKey;
// Connect to the database
using (var connection = new SqlConnection(connectionString))
using (SqlDataAdapter da = new SqlDataAdapter("SELECT ID, Name, Token, ClientID, ClientInfo, Owner, OtherID, Prefix, GoogleApi FROM dt", connection))
{
SqlCommandBuilder cb = new SqlCommandBuilder(da);
connection.Open();
DataTable dt = new DataTable();
// Load then modify the data
da.Fill(dt);
dt.Rows[0].BeginEdit();
dt.Rows[0][1] = PropertiesList[0];
dt.Rows[0][2] = PropertiesList[1];
dt.Rows[0][3] = PropertiesList[2];
dt.Rows[0][4] = PropertiesList[3];
dt.Rows[0][5] = PropertiesList[4];
dt.Rows[0][6] = PropertiesList[5];
dt.Rows[0][7] = PropertiesList[6];
dt.Rows[0][8] = PropertiesList[7];
dt.Rows[0].EndEdit();
// Put the data back
try
{
da.AcceptChangesDuringUpdate = true;
da.DeleteCommand = cb.GetDeleteCommand(true);
da.UpdateCommand = cb.GetUpdateCommand(true);
da.InsertCommand = cb.GetInsertCommand(true);
dt.AcceptChanges();
da.Update(dt);
MessageBox.Show("Properties Updated", "Update"); //this completes fine and displays the updated message
}
catch
{
MessageBox.Show("Cant Store data", "Error");
}
connection.Close();
}
}
Sorry about the messy code I've been adding things in to try to fix this but I have not had any success.
You shouldn't be calling AcceptChanges before the Update, so you need to remove dt.AcceptChanges();
A longer answer is that the AcceptChanges will mark all the added and updated rows as now being unmodified, and it will permanently delete the rows you've asked to be deleted (from the datatable -- not the table in Sql Server). Then when you call Update, it scans the databable looking for any rows that are in "Added", "Modified" or "Deleted" status, and finds there are none (because you just changed them all to "Unmodified" via AcceptChanges), so nothing is sent to the database.

While in the Front End, how do you retrieve a DataSet returned by a WebMethod?

Within the Web Service, I am returning a DataSet using a WebMethod. However, I need to access that DataSet in the FrontEnd. How do I do this?
WebMethod:
[WebMethod]
public DataSet customerInformation(string orderNo)
{
try
{
SqlConnection myConnection = new SqlConnection(ConfigHelper.GetConnection());
myConnection.Open();
SqlDataAdapter adapter = new SqlDataAdapter("listTheCustomerNumber", myConnection);
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parametersGroup = new SqlParameter("#orderNo", SqlDbType.VarChar, 10);
parametersGroup.Value = orderNo;
adapter.SelectCommand.Parameters.Add(parametersGroup);
// Create and Fill the DataSet
DataSet myDataSet = new DataSet();
adapter.SelectCommand.CommandTimeout = 240;
adapter.Fill(myDataSet);
myConnection.Close();
return myDataSet;
}
catch (Exception excep)
{
throw new System.FormatException("Error reading DataBase!", excep);
}
}
FE:
Step 1: Create event method for handling button click.
Step 2: Proxy call.
Step 3: I got nothing.
Never mind! Went brain-dead and forgot to update the WS within the Web References folder.
You may receive an error when you try it at first, so just run the program, copy the link into another browser, then close the window you originally emulated your code with.
After that just right-click the WS and select Update, and you should be good to go!

I get no errors when adding a row to a DataTable, but the row is not added to the database

I am trying to add a row to a table in a PostgreSQL database using ODBC. Although no exceptions are thrown, the row is not being added to the table. Here is my code:
void TestNewRow()
{
try
{
DataSet dataSet = new DataSet();
OdbcDataAdapter adapter = new OdbcDataAdapter();
adapter.SelectCommand =
new OdbcCommand("select read_time from plant_genie.plc_values_by_tag", m_db.GetConnection());
OdbcCommandBuilder builder =
new OdbcCommandBuilder(adapter);
adapter.Fill(dataSet);
DataTable valuesTable = dataSet.Tables[0];
DataRow newRow = valuesTable.NewRow();
newRow["read_time"] = DateTime.Now;
valuesTable.Rows.Add(newRow);
valuesTable.AcceptChanges();
dataSet.AcceptChanges();
adapter.Update(dataSet);
}
catch (Exception ex)
{
int a = 1;
}
}
I have a breakpoint in the exception handler and another at the end of the function. The second breakpoint is hit but not the first, so no exception is being thrown. I have triple-checked that I'm connecting to the correct database. I don't think I should need two AcceptChanges() calls and an Update() call, but even with all of that overkill, I'm still not getting a new row in my table. What am I doing wrong?
I tried to find a duplicate of this question, but there are so many questions about adding rows that if there was a duplicate, it is being hidden.
Thank you for your help.
RobR
Calling AcceptChanges marks all changes as accepted (i.e. it resets the state of everything to Unmodified), so no changes will be saved to the database. Remove this call to both the table and dataset and your changes should be saved.

Moving Data from DataSet to Oracle Database using C#

I've been squeezing my mind trying to figure out why my code isn't working.
I am trying to read from a DataSet that filled with data from access database and insert the data into an Oracle database which is created previously.
When I try the following code it won't work and although I use the try and catch block, when debugging it would freeze and won't show me any error.
if can see that I have commented out the block just right above my foreach loop..which works perfectly, Any help from you is so much appreciated :
private void button3_Click(object sender, EventArgs e)
{
string query1 = "Select * from Test;";
string StrQuery= "Insert Into TEST (ID, DATA) Values (:ID, :DATA)";
Conn = new OleDbConnection(connStr);
Conn.Open();
using (OleDbConnection connection1 = new OleDbConnection(connStr))
{
using (OleDbDataAdapter adapter1 = new OleDbDataAdapter(query1, connection1))
{
DataSet ds1 = new DataSet();
adapter1.Fill(ds1);
// no need for refilling DataGridView1.DataSource = ds.Tables[0]
// insterting the dataset into oracle
try
{
using (OracleConnection connect = new OracleConnection(oradb1))
{
connect.Open();
using (OracleCommand comma = new OracleCommand(StrQuery, connect))
{
/*comma.Parameters.Add(new OracleParameter(":ID", 2));
comma.Parameters.Add(new OracleParameter(":DATA", 2));
comma.ExecuteNonQuery();*/
foreach (DataRow drRow in ds1.Tables[0].Rows)
{
for (int i = 0; i < ds1.Tables[0].Columns.Count; i++)
{
comma.Parameters.Add(new OracleParameter(":ID", drRow[i]));
comma.Parameters.Add(new OracleParameter(":DATA", drRow[i]));
comma.ExecuteNonQuery();
}
}
connect.Close();
connect.Dispose();
}
}
}
catch (OracleException)
{
System.Diagnostics.Debugger.Break();
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Conn.Close();
}
You are looping columns but adding the drRow[i] as values in the parameters.
I do not think this is what you intended.
skip the columns loop and add the first column value to id and second column value to data.
that should be what you wanted.... if not then describe a bit more...
Expanding on Judgemaik's answer, I believe you need to do something like this instead (can't really tell what the names of the columns in your access table are but you get the idea:
foreach (DataRow drRow in ds1.Tables[0].Rows)
{
comma.Parameters.Add(new OracleParameter(":ID", drRow["IDColumnFromAccessDB"]));
comma.Parameters.Add(new OracleParameter(":DATA", drRow["DATAColumnFromAccessDB"]));
comma.ExecuteNonQuery();
}
A similar approach is outlined in my answer here. In that particular case I was moving data from SQL Server Compact into Access, but the same idea could very well be used to move data between any two OleDb data sources.
It uses an OleDbDataAdapter to pull the source table into a DataTable, copies it over to another DataTable, and then uses another OleDbDataAdapter to update the corresponding table in the destination database.

C# passing information

Sorry in advance im going to try and explain this as best as possible....
I have 2 asp.net pages one named membermaster and the second named memberdetails. I created a class library which contains 2 functions
My first function returns a list depending on the search result...
I added a linkbutton to the gridviews first column which when clicked it passes through querystring the membershipgen. What i wanted to do is for my second function i created this
public DataTable GetMembers(int MEMBERSHIPGEN)
{
DataTable table = null;
SqlConnection con = null;
SqlCommand cmd = null;
SqlDataAdapter ad = null;
SqlParameter prm = null;
try
{
table = new DataTable();
using (con = new SqlConnection(connectionString))
{
using (cmd = new SqlCommand("usp_getmemberdetail", con))
{
using (ad = new SqlDataAdapter(cmd))
{
prm = new SqlParameter("#MEMBERSHIPGEN", SqlDbType.Int);
prm.Value = MEMBERSHIPGEN;
cmd.Parameters.Add(prm);
ad.Fill(table);
}
}
}
}
catch (Exception ex)
{
//write your exception code here
}
return table;
}
In the attempt to try and send the membershipgen to this and it return the results. But once i compile the DLL and add it to my project I am not sure how i would reference this function to populate individual textboxes and labels with the information.
What I am trying to do is when a user clicks the viewdetails button on the gridview I can then use that membershipgen that I passed through querystring to populate the page through a stored procedure but the smarts would be stored in a DLL.
You probably want your method to return a value. Currently the return type is void, so the values it populates internally just go away when the call stack leaves the method. It sounds like you want something like this:
public DataTable GetMembers(int MEMBERSHIPGEN)
Then, in your method, after you've populated the DataTable and exited the using blocks, you'd do something like this:
return table;
This would return the DataTable to whatever called the method. So your page would have something like this:
DataTable table = GetMembers(membershipgen);
So the page would be responsible for:
Get the membershipgen value from the input (query string)
Call the method and get the result of the method
Display the result from the method (bind to a grid? or whatever you're doing to display the data)
And the method is responsible for:
Interact with the database
This is a good first step toward the overall goal of "separation of concerns" which is a very good thing to do. You can continue down this path by always asking yourself what each method, class, etc. should be responsible for. For example, your GetMembers method should also be responsible for ensuring that the value passed to it is valid, or that the value returned from it is not null.
You need to change GetMembers to return data instead of void. If you want to use DataTables, you can just modify your code to this:
public DataTable GetMembers(int MEMBERSHIPGEN)
{
DataTable table = new DataTable();
SqlConnection con = new SqlConnection(connectionString);
using (SqlCommand cmd = new SqlCommand("usp_getmemberdetail", con))
{
using (SqlDataAdapter ad = new SqlDataAdapter(cmd))
{
SqlParameter prm = new SqlParameter("#MEMBERSHIPGEN", SqlDbType.Int);
prm.Value = MEMBERSHIPGEN;
cmd.Parameters.Add(prm);
ad.Fill(table);
return table;
}
Then in your Page_Load it might be something like this (more robust than this hopefully):
{
DataTable table = yourDll.GetMembers(Convert.ToInt32(Request.QueryString["membership"]));
label1.Text = Convert.ToString(table.rows[0]["Name"]);
}
One way to go might be to construct the button so that it navigates to a url along the lines of:
http://localhost/DetailPage.aspx?membershipgen=4
Then in the load of the DetailPage.aspx:
Page_Load(Object sender, EventArgs e)
{
if (!this.IsPostback)
{
int membershipgen;
if (int.TryParse(Request.QueryString["membershipgen"], out membershipgen)
{
//Get the data (replace DataAccess with the name of your data access class).
//Also, you probably want to change GetMembers so it returns the data.
DataTable table = DataAccess.GetMembers(membershipgen);
//TODO: Display the results
}
}
else
{
//Display an error
}
}

Categories

Resources