CommandTimeout not working when using SqlDataAdapter to fill a DataTable - c#

I am setting CommandTimeout to 1 second and no TimeoutException is being thrown as expected. The query I am running takes about 7-8 seconds. The timeout does work however when I use ExecuteReader to execute a query rather than trying to fill a DataTable. I have tried setting CommandTimeout when after creating the command and also after creating the DataAdapter.
using(SqlConnection con = new SqlConnection("data source=*****;user id==*****;password==*****;initial catalog==*****;"))
{
string query = "select * from *****";
SqlCommand command = new SqlCommand(query, con);
//command.CommandTimeout = 1;
CostingDataSet cds = new CostingDataSet();
SqlDataAdapter da = new SqlDataAdapter(command);
da.SelectCommand.CommandTimeout = 1;
Stopwatch stopwatch = Stopwatch.StartNew();
da.Fill(cds.CostingData);
stopwatch.Stop();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

The cause is the magic that occurs in the SQLDataAdapter, which is frankly, why they are a bad idea.
My guess is they are using async to perform the fill, which will always ignore command timeouts.
My suggestion: run away from the adapter, and never look back. They aren't that valuable and make everything messier.
If that isn't possible, set your connection timeout in your connection string and it should apply regardless of how the db is accessed.

Queries like "select * from" are a bad idea.
What is the reason not to use select *?
That said, maybe you could restric the amount of data to return, by paging or similar way. Reducing the amount of returned data will make it work

Related

How do I delete an entire row from a database

How would I delete a row from a sql database, either with stored procedures or without, right now I have tried without, using a button press.
This is what I have so far, _memberid has been sent over from a differnt form from the database(For context).
private void btnDelete_Click(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = Lib.SqlConnection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "Delete * From Members where MemberId = " + _memberId;
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.DeleteCommand = cmd;
adapter.Fill(MembersDataTable); // Im fairly sure this is incorrect but i used it from old code
DialogResult = DialogResult.OK;
}
If you're trying to do a simple ADO.Net-based delete, then it would be somehting like his:
private void DeleteById(int memberId)
{
// or pull the connString from config somewhere
const string connectionString = "[your connection string]";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = new SqlCommand("DELETE FROM Members WHERE MemberId = #memberId", connection))
{
command.Parameters.AddWithValue("#memberId", memberId);
command.ExecuteNonQuery();
}
}
Use parameter to prevent SQL injection.
There are essentially three main things I'm seeing...
One
You don't need the * in the query. DELETE affects the whole row, so there's no need to specify columns. So just something like:
DELETE FROM SomeTable WHERE SomeColumn = 123
Two
There's no need for a SqlDataAdapter here, all you need to do is execute the query. For example:
cmd.ExecuteNonQuery();
The "non query" is basically a SQL command which doesn't query data for results. Inserts, updates, and deletes are generally "non queries" in this context. What it would return is simply the number of rows affected, which you can use to double-check that it matches what you expect if necessary.
Three
Don't do this:
cmd.CommandText = "Delete From Members where MemberId = " + _memberId;
This kind of string concatenation leads to SQL injection. While it looks intuitively like you're using _memberId as a query value, technically you're using it as executable code. It's less likely (though not impossible) to be a problem for numeric values, but it's a huge problem for string values because it means the user can send you any string and you'll execute it as code.
Instead, use query parameters. For example, you might do something like this:
cmd.CommandText = "Delete From Members where MemberId = #memberId";
cmd.Parameters.Add("#memberId", SqlDbType.Int);
cmd.Parameters["#memberId"].Value = _memberId;
This tells the database engine itself that the value is a value and not part of the executing query, and the database engine knows how to safely handle values.
You could use a DataAdapter, but since you aren't using a datatable, it's just easier to do it without like this:
var sql = "DELETE FROM Members WHERE MemberId=#MemberId";
using(var cmd = new SqlCommand(sql, Lib.SqlConnection))
{
cmd.Connection.Open();
cmd.Parameters.Add("#MemberId",SqlDbType.Int).Value = _memberId;
cmd.ExecuteNonQuery();
}
And if you are using Dapper, you can do this:
Lib.SqlConnection.Execute("DELETE FROM Members WHERE MemberId=#MemberId", new {MemberId=_memberId});
If you are still using DataTables, I would highly recommend you look into using this (or something like this) to simplify your database accesses. It'll make CRUD logic on a database a breeze, and your code will me a lot more maintainable because you can get rid of all the odd needs to do casting, boxing/unboxing, and reduce the chances of runtime bugs because of the use of magic strings that happens so often with DataTables (column names). Once you start working with POCO classes, you'll hate having to use DataTables. That said, there are a few places where DataTables are a better solution (unknown data structures, etc), but those are usually pretty rare.

Application level optimization

what is the best way to call a stored procedure and still have a very low response time in asp.net ? i have tried filling a dataset from an adapter:
SqlConnection conn = new SqlConnection(dbm.ConnectionString);
SqlCommand sqlcom = conn.CreateCommand();
sqlcom.CommandType = CommandType.StoredProcedure;
sqlcom.CommandText = "";
sqlcom.Parameters.Add(new SqlParameter("#SOME_ID", Session[IWConstants.SessionAccountID]));
sqlcom.Parameters.Add(new SqlParameter("#END_DATE", ""));
sqlcom.Parameters.Add(new SqlParameter("#FILTER_OPTION", ""));
sqlcom.Parameters.Add(new SqlParameter("#START_DATE", ""));
SqlDataAdapter sqlDA = new SqlDataAdapter(sqlcom);
DataSet ds = new DataSet();
sqlDA.Fill(ds);
csvDataTable = ds.Tables[0];
and this block is giving me 11,000 plus milli seconds in response is there a better way of doing it ??
What you have written is definitely one of the most efficient ways. I assume that you acrually set the CommandText to the name of your stored procedure.
Your response time probably has to do with either network topology or available sql server resources. (Assuming your sp excutes on very short time when tested directly on the sql server.)
Check out the second table on this page http://ormeter.net/ to see how much an ORM adds to execution time if that is what you are considering that as an option.
If you want to micro-optimize what happens in client code you could use a datareader instead of filling a dataset. That has slightly lower overhead, but in comparison to accessing the database it's usually negligable.

Parameters cause sql query to time out

I have a long SQL query, it does some inserts, updates, then deletes. Each query uses the same 2 parameters. If I pass them in as SQL parameters from C#, it times out, after 20 mins. I just put the parameters into the command text, and it works. When I use it with the parameters it doesn't even show up in the profiler till it times out. Am I missing something?
SqlCommand comm = new SqlCommand(cmdText, conn);
comm.CommandTimeout = 5 * 60;
SqlParameter p = new SqlParameter("#key1", SqlDbType.Int);
p.Value = key1;
comm.Parameters.Add(p);
p = new SqlParameter("#key2", SqlDbType.Int);
p.Value = 1000000;
comm.Parameters.Add(p);
comm.ExecuteNonQuery();
If you take the parameter code out, and just to a replace on cmdText before executing the query it works. The query itself is a 300 lines or so. Each parameter gets used 51 times.
You may be missing the comm.Prepare() call before ExecuteNonQuery().
The key is in the SQL command, instead of saying "cmdText" post your SQL command.
EDIT: You are also not specifying a parameter direction in the code, it might be important.
Did you set the command type?
var command = new SqlCommand() { CommandType = CommandType.StoredProcedure };

MySQL query timeout

I'm trying to execute a query using C#. The problem is that, despite the fact that I modified the timeout period, it thrown a timeout exception. It is rising the exception after 30 seconds, that is the default value.
using (MySqlConnection conn = new MySqlConnection(connStr))
{
int x = conn.ConnectionTimeout;
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "SELECT AVG(v.value_min) AS minValue FROM values v";
adpter.SelectCommand = cmd;
adpter.Fill(dados);
conn.Close();
}
As you can see, I'm using conn.ConnectionTimeout to check if the timeout is properly configured and, yes it is. At least it shows the amount of time that I configured (in that case 90).
So, how do I do this? How to run a long time query?
UPDATE: The query that I posted is just an example.
Setting the CommandTimeout property on your MySqlCommand instead of the connection should do the trick.

Help with DataAdapter - DB doesn't update?

I have a data adapter. When I check the function at runtime I see the changes, but nothing happens in the database. How do I debug this? What went wrong?
OleDbDataAdapter adapter = new OleDbDataAdapter();
string queryString = "SELECT * FROM tasks";
OleDbConnection connection = new OleDbConnection(cn.ConnectionString);
adapter.SelectCommand = new OleDbCommand(queryString, connection);
OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter);
connection.Open();
adapter.Fill(ds.Tables["Tasks"]);
adapter.Update(ds);
return ds;
Nothing is happening in the database because you're running a SELECT query. What are you expecting to happen?
Well unless you snipped a lot of code, you are not changing anything in the dataset per se.
What are you trying to achieve?
Here, you are selecting some data, filling the dataset with it, then putting back the unchanged dataset in the DB.
You should first change something in the dataset itself before calling adapter.Update(ds)
Cheers,
Florian
You are selecting data via the SelectCommand. If you want to update data, you need to run the UpdateCommand.
I assume you didn't post the full source code, as it looks as though you're not modifying the dataset. However, I just tweaked your code a bit (see my comments).
Hopefully this will help...
string queryString = "SELECT * FROM tasks";
OleDbConnection connection = new OleDbConnection(cn.ConnectionString);
connection.Open(); // open connection first
SqlCommand cmd = new SqlCommand(queryString, connection);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd); // use the cmd above when instantiating the adapter
OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter);
adapter.Fill(ds.Tables["Tasks"]);
// Modify your dataset here.
// Don't call AcceptChanges() as this will prevent the update from working.
adapter.Update(ds);
connection.Close(); // Close connection before ending the function
return ds;
This should allow OleDbCommandBuilder to do its thing by automatically scripting the database updates.
As far as I can see you've not actually changed any of the contents of the tasks table. When you call adapter.Fill you are populated the empty dataset with the records from the database. You are then calling adapter.Update without changing any records within the dataset. The update command only performs changes when the dataset > datatable > datarows are edited and marked as dirty.
you are only specifying the select command. you also need to specify the insert command... i.e:
DataAdapter.InsertCommand = new OleDbCommand....

Categories