Why can SqlDataAdapter.Update only be called Once? - c#

I have a C# ASP.net project that sends a dataset to my connection class where I update the database accordingly.
The dataset I send through is populated with data from 2 tables from my database, thus I used a Join to get the data. (thus the individual update)
Now I have made the changes I want to the dataset and want to Update the database. Both section 1 and 2 of my code works IF only one is run at a time (thus either section 1 or 2 should be commented out).
But when I try and run both, it only updates the database with the first part (no error is thrown, and the code does execute)
Why does this happen? I've also closed and re-opened my connection after the first update to see if that made any difference.
public void udpateCourse(DataSet dataSetEmp)
{
try
{
conn.Open();
//SECTION 1 -- THE FIRST UPDATE
da = new SqlDataAdapter("select * from EthicsManagement", conn);
var builderForTable1 = new SqlCommandBuilder(da);
da.Update(dataSetEmp, "Table");
//SECTION 2 -- THE SECOND UPDATE
da = new SqlDataAdapter("select employeeId, name as [Employee Name] from EmployeeTable", conn);
builderForTable1 = new SqlCommandBuilder(da);
da.Update(dataSetEmp, "Table");
conn.Close();
}
catch (Exception ex)
{
throw new Exception("Problem with the SQL connection " + ex);
}
}
--Update--
What I've Tried
Closing and opening the connection again
New Instances of the adapter and builders
even putting them in a separate method
Having one query (a join on two tables)

I know it's an old question, but perhaps it helps someone.
MSDN says the following happens when calling Update:
When using Update, the order of execution is as follows:
The values in the DataRow are moved to the parameter values.
The OnRowUpdating event is raised.
The command executes.
If the command is set to FirstReturnedRecord, then the first returned result is placed in the DataRow.
If there are output parameters, they are
placed in the DataRow.
The OnRowUpdated event is raised.
AcceptChanges is called.
The second Update() doesn't have any effect, because the changes to it were committed by the AcceptChanges() command.

Related

OracleDataAdapter, Fill method hangs, how do I handle connection terminations/drop offs/cut outs?

I have a C# program that connects to a remote server to query data. The data is quite big so the query takes about 2 mins to finish. During this 2 min window, the internet went down. This resulted in the job being unable to finish with the program stuck in the getting data routine.
It established connection but during the select query it was cut off. Setting the command timeout to 30 seconds did not work. I need the query to fail when encountering this error because the program can handle failure but it cannot handle being stuck. Thanks!
UPDATE: included code
OracleConnection connection = new OracleConnection(connectionstring);
OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(new OracleCommand(query, connection));
oracleDataAdapter.SelectCommand.CommandTimeout = 30;
DataSet dataSet = new DataSet();
try
{
oracleDataAdapter.Fill(dataSet, table); //Hangs on this line when connection is lost
return dataSet;
}
catch
{
throw;
}
finally
{
dataSet.Dispose();
oracleDataAdapter.Dispose();
}
UPDATE AGAIN:
What I need to do is handle this situation because I don't want a dangling process.
Simplest would be once the connection is lost is that the program will throw an error. That is what I don't know how to do. I assumed that the commandtimeout will fix it but it did not.
There are a few duplicates reporting this problem, eg: System being hang when the connection is lost while adapter is filling the datatables
I found a good thread on MSDN where the OP answers:
I have solved this problem a while back, sorry i forgot to come and let you all know. I worked out that the code stopped executing at that line because (for some reason) there was already an open connection to the database.
Since DA.Fill would open a connection itself if there wasnt one previously opened, it was having a hissy fit and bombing out.
I solved this by putting Connection.Close(); before and after any connection to the database is needed.
Based on this we can see you are not explicitly opening a Connection to the Database. Suggest you do a:
connection.Open();
Also follow Steve Py's answer with the using to confirm you are closing the connection and disposing unmanaged resources.
I see a couple issues with your statement, assuming it's using ODP.Net. Try the following:
DataSet dataSet = new DataSet();
using (OracleConnection connection = new OracleConnection(connectionstring))
{
using (OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(new OracleCommand(query, connection)))
{
oracleDataAdapter.Fill(dataSet, table);
}
}
return dataSet;
The using blocks will handle disposing of the connection and data adapter. In your example the connection did not get disposed which may have been part of your issue. Additionally I don't think you want to dispose the dataset if you intend to return it.
Since you were bubbling up the exception with a Throw I removed the exception handling. Keep in mind that this will bubble the exception so somewhere in your calling code chain you will need to catch the exception and handle it. If the app is just sitting there then be wary of any empty "catch" blocks eating exceptions.
Updated answer:
DataSet dataset = new DataSet();
using (OracleConnection connection = new OracleConnection(connection))
{
using (OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(new OracleCommand(query, connection)))
{
oracleDataAdapter.SelectCommand.CommandTimeout = 30;
connection.Open();
oracleDataAdapter.Fill(dataset, table);
}
}
return dataset;

.NET SQL connection code is blocking all other connections

Apologies if the subject does not accurately reflect my exact issues, I'm struggling to explain the issue I'm having, although it seems quite straight-forward.
I've built a simple "db helper" class which executes sql statements for me, given some parameters, etc. Here's the code block:
public DataSet selectSprocData(string sprocName, SqlParameter[] parameterArray, out int returnValue)
{
//processes the specified Select stored procedure based on parameter array provided;
//this is the only place anywhere in the application we will do a simple SELECT using a sproc.
DataSet dataset = new DataSet();
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyServer"].ToString()))
{
cn.Open();
SqlDataAdapter adapter = new SqlDataAdapter(sprocName, cn);
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.SelectCommand.Parameters.AddRange(parameterArray);
SqlParameter retValParam = adapter.SelectCommand.Parameters.Add("#RETURN_VALUE", SqlDbType.Int);
retValParam.Direction = ParameterDirection.ReturnValue;
adapter.SelectCommand.CommandTimeout = 600;
adapter.Fill(dataset);
returnValue = (int)retValParam.Value;
adapter.Dispose();
cn.Close();
}
return dataset;
}
When I take a long-running sproc and execute it within SSMS it will run and eventually time out. Meanwhile I can open another query window in SSMS and execute any other select or queries against my db.
Now, when I call this sproc through my web-app using the code-block above it, the page will spin and load and load until eventually (a few minutes later) the process will time out.
However, during this web-based call I can NOT open any other window and execute any other UI functions that use the same db-code to call other sprocs.
Essentially, one user executing a sproc/function from the UI which takes long seems to be blocking everyone else from doing anything on my app.
I understand that first and foremost I need to have better queries that don't time out, but is there something I'm missing or not doing right in .net/c# that would be causing all other connections or command attempts to be blocked until the other one has finished or timed out?
My web.config connectionstring has no special parameters, simply:
Persist Security Info=False;User ID=sa;Password=xxxx;Initial Catalog=db_live;Data Source=my.host.com"
Any help would be greatly appreciated
You can't really compare a Windows Application (SQL Management Studio) to an ASP.NET web app (running in IIS)
ALl of your ASP.NET code is running on a single thread, so that thread has to wait for the database code to complete, which blocks all everything else, until it's done.
Use an ASP.NET Update panel to perform your long running stored procedure and UI binding.
ASP.NET Update Panel

What happens if I dont open instance of SqlConnection?

I am reviewing a piece of code in a application and I came to something very strange in regard to connecting to database.
It is executing queries without opening the connection like this:
using (sqlConnection1 = new SqlConnection(connString)
{
SqlCommand comm = new SqlCommand(query,sqlConnection1);
// ... parameters are handled here...
SqlDataAdapter ad = new SqlDataAdapter(comm);
ds = new DataSet();
ad.FillSchema(ds, SchemaType.Source);
ad.Fill(ds);
}
Shouldnt it fail because of connection is not open? I actually tested this in separate project and it worked.
If the connection is closed, using SqlDataAdapter.Fill will open the connection
http://msdn.microsoft.com/en-us/library/377a8x4t.aspx
Per the documentation, SqlDataAdapter will open the conenction if it isn't already open, and return it to its previous state.
The connection object associated with the SelectCommand must be valid, but it does not need to be open. If the connection is closed before FillSchema is called, it is opened to retrieve data, then closed. If the connection is open before FillSchema is called, it remains open.
Fill also behaves in the same manner
Refer MSDN
The Fill method implicitly opens the Connection that the DataAdapter
is using if it finds that the connection is not already open. If Fill
opened the connection, it will also close the connection when Fill is
finished. This can simplify your code when dealing with a single
operation such as a Fill or an Update.
This means that after da.Fill(ds, "Test"); your connection is closed by the method itself. But you need it open for the following Update (and that fails)
From SqlDataAdapter.Fill method;
The Fill method retrieves rows from the data source using the SELECT
statement specified by an associated SelectCommand property. The
connection object associated with the SELECT statement must be valid,
but it does not need to be open. If the connection is closed before Fill is called, it is opened to retrieve data, then closed. If the
connection is open before Fill is called, it remains open.
Also FillSchema method does same thing.

SQL CPU peaks with SqlDataAdapter.Fill Command

I've noticed some peculiar behaviour getting SQL data into a c# application. I used a dataset xsd but this began to time out. I then changed my approach as I already had a class which would generate and return a datatable for other operations I tried that. This too timed out.
I had opened the Activity Monitor in SSMS to get an idea of what was happening in SQL when the code ran and noticed that which ever way I run it the fill command casuses the SQL Sever to peak at 100% CPU and stay there until the command is cancelled. This is a good server with plenty of oomph 240Ghz processors and 30GB RAM . The query is not exactly zippy but returns 100k rows in under 3 seconds in SSMS.
Here is my code for the dataset:
public DataTable UKDataRefresh ()
{
UKREFRESH.UKNewContactsDataTable dt =
new UKREFRESH.UKNewContactsDataTable();
UKREFRESHTableAdapters.UKNewContactsTableAdapter ta =
new UKREFRESHTableAdapters.UKNewContactsTableAdapter();
ta.Connection.ConnectionString += ";Password = xxxxxx;";
try
{
ta.Fill(dt, global::SilverPopTransfer.Properties.Settings.Default.UKDATELASTACTION);
}
catch (SqlException )
{
throw;
}
return dt;
}
Here is my code for building it on the fly:
public DataTableOperations (string strconnection, string strSelect,string tablename)
{
SqlConnection c = new SqlConnection(strconnection);
connection = c;
SqlDataAdapter da = new SqlDataAdapter(strSelect, connection);
DataSet ds = new DataSet();
//added this to see what would happen.
da.SelectCommand.CommandTimeout = 0;
connection.Open();
da.Fill(ds, tablename);
connection.Close();
Datatable = ds.Tables[tablename];
_disposed = false;
}
Im looking for clues as to what might cause the problem, not a full solution.
Incidentally I ran a similar function in a pre-existing console application before posting and it connected and ran without error: the query was almost identical.
The sole difference is that for the pre-existing application I use Integrated security but in this case I specify the user and password. I have confirmed the login credentials.
Check index and set nocount on before execution. SSMS performance is not a good performance indicator. It get only partial data and executes asynchronous. Try calling a small subset of data or running the query without to fill the table. It can be the bottleneck.
If your are running the select with parameters, sql server will execute it using sp_execute then server compile it creating CPE peaks.

When is SqlCommand.StatementCompleted supposed to fire?

Update Do I have to clarify something in my question? I'm amazed to see I didn't get any rating, comment or answer in two weeks time.
I'm trying to write a simple winforms application that executes a SQL SELECT statement asynchronous. When the sql server starts returning results, I want to execute an event handler I've wired up to the SqlCommand's StatementCompleted event.
The form contains two buttons, a textbox, and a label. When button1 is clicked, I create the SqlCommand and wire up the event handler, then I open the SqlConnection and call BeginExecuteReader in order to start the asynchronous operation. I set my label to show the command is executing.
In the event handler, I simply set the label to show the command is finished.
When button 2 is clicked, I change the label to show we're processing the results. Then I call EndExecuteReader and assign its return value to a new SqlDataReader which I then process.
What I see is that the event handler doesn't get called when the command is ready. In stead, it gets called when my code finishes processing the reader returned by EndExecuteReader.
Am I missing something here? Do I misinterpret the intended use of the event? I've tried to find an example of StatementCompleted, but I could only find general descriptions of it, no working code. The example at the SqlCommand.BeginExecuteReader page at MSDN uses a loop and waits for the IAsyncResult.IsCompleted property to be true. I would expect that at the same time that property gets true, the StatementCompleted event fires.
public Form1() {
InitializeComponent();
}
private IAsyncResult iAsyncResult;
private SqlCommand sqlCommand;
private void statementCompleted(object sender,
StatementCompletedEventArgs e) {
label1.Text = "Statement completed";
}
private void button1_Click(object sender, EventArgs e) {
var northWindConnection =
new SqlConnection(
"Data Source=.\\SqlExpress;Initial Catalog=Northwind;" +
"Integrated Security=True;" +
"asynchronous processing=true");
sqlCommand = new SqlCommand("WAITFOR DELAY '00:00:05';" +
" SELECT * FROM [Order Details]",
northWindConnection);
sqlCommand.StatementCompleted += statementCompleted;
northWindConnection.Open();
iAsyncResult = sqlCommand.BeginExecuteReader();
label1.Text = "Executing";
}
private void button2_Click(object sender, EventArgs e) {
label1.Text = "Not waiting anymore, reading";
var results = new StringBuilder();
var reader = sqlCommand.EndExecuteReader(iAsyncResult);
while (reader.Read()) {
for (int i = 0; i < reader.FieldCount; i++) {
results.Append(reader[i].ToString() + "\t");
}
results.Append(Environment.NewLine);
}
reader.Close();
sqlCommand.Connection.Close();
textBox1.Text = results.ToString();
}
The sequence of events is this:
Call SqlCommand.BeginExecuteReader(callback, stateObject) sends the T-SQL to SQL Server and the command starts executing.
When data is first available, the AsyncCallback provided to BeginExecuteReader() is called.
The callback invokes EndExecuteReader() to obtain a reference to a SqlDataReader object.
You use the SqlDataReader to read the results of the query. This could be one row, or millions of rows. The query is not complete until all data requested has been returned.
Repeat for additional result sets, if any.
Invoke the StatementCompleted event -- but only if the query / stored procedure did not use SET NOCOUNT ON.
In other words, StatementCompleted is called when the T-SQL has completely finished, including all associated data transfers.
Adding this for anyone that might run across this question since it was asked months ago with no answers provided.
The StatementCompleted event isn't useful in applying an async call pattern against SqlCommand. It does get fired but only during the call to EndExecuteReader which is basically too late. If you want to implement an async call pattern in general, this MSDN article has an excellent explanation of how it can be done. The sample code in the BeginExecuteReader documentation shows the correct usage of SqlCommand in an async mode.
I suspect the clue to this behaviour is that the event's "StatementCompletedEventArgs" parameter includes the property "RecordCount" which is the number of rows affected by a statement.
MS SqlServer (and before that Sybase SqlServer, as it then was) returns the number of rows affected as a separate "message" (using the term loosely) after the actual data has all been sent.
Also, beware: A Sql Command can consist of a number of SQL Statements, each of which can affect a number of rows and therefore return a number of "rows affected". I would therefore assume the event might fire several times for a given SQL Command; or no times at all is SET NOCOUNT ON was used.

Categories

Resources