Query Timing out when Command Timeout = 0 - c#

I have a frustrating issue with a query that typically takes between 1.5-2 minutes to run (due to a lack of ability to modify this database, we cannot improve it more than this time). The query times out, despite the Command Timeout property being set to 0 (this is C# code).
Here is the code that executes the query:
public DataTable GetData()
{
DataTable results = new DataTable();
try
{
using (var sqlConnection = new SqlConnection(ConfigurationManager.AppSettings["SqlConnectionString"].ToString()))
{
String command = _query;
sqlConnection.Open();
var sqlCommand = sqlConnection.CreateCommand();
sqlCommand.CommandText = command;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandTimeout = 0;
SqlDataAdapter daM = new SqlDataAdapter(sqlCommand.CommandText, sqlConnection);
daM.Fill(results);
sqlConnection.Close();
}
}
catch(Exception e)
{
Console.WriteLine("Error " + e.StackTrace);
}
Console.WriteLine("Retrieving results for query " + _query);
Console.WriteLine("Total Results: " + results.Rows.Count);
return results;
}
I'm not sure where to look for the culprit. Setting a more explicit timeout does nothing, and as I said there's no way to further improve the query that we've been able to find. The connection string has the following parameters:
server =
Integrated Security = SSPI
database =
Connection Timeout = 0
Any advice of where I should look next? We are using Microsoft SQL Server.

You have set sqlCommand.CommandTimeout, but later you've created SqlDataAdapter as
SqlDataAdapter daM = new SqlDataAdapter(sqlCommand.CommandText, sqlConnection)
Here adapter implicitly creates and uses new SqlCommand (not the one you've configured) since you've passed there command text, not instance of SqlCommand.
Use another constructor of SqlDataAdapter and create it like
SqlDataAdapter daM = new SqlDataAdapter(sqlCommand)

Set timeout on SqlConnection does not work in your case, you need do it on SqlDataAdapter.
daM.SelectCommand.CommandTimeout = Value;
Google for "How do you change a SqlDataAdapter .CommandTimeout?"

Related

How to call 3 different stored procedure in one database connection?

I have a c# console app client and I am trying to connect to mysql database.
I have a main method called select.
This method return n of rows.
I am looping through results, and for each one I am calling another method call GetProductAttributes and after I get the results I am calling another method called UpdateProductAttributesJsonField
Here is my code :
public void Select(int shopId)
{
using(MySqlCommand cmd = new MySqlCommand("GetProducts", new MySqlConnection(connection.ConnectionString)))
{
cmd.Parameters.Add(new MySqlParameter("#last_modified_date", ""));
cmd.Parameters.Add(new MySqlParameter("#ShopId", shopId));
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection.Open();
MySqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dataReader.Read())
{
var id = int.Parse(dataReader["Id"].ToString());
var attributes = GetProductAttributes(id);
var json = JsonConvert.SerializeObject(attributes.ToArray());
UpdateProductAttributesJsonField(id, json);
}
//dataReader.Close();
}
}
public Dictionary<string, string> GetProductAttributes(int Id)
{
var result = new Dictionary<string, string>();
using(MySqlCommand cmd = new MySqlCommand("GetProductAttributes", new MySqlConnection(connection.ConnectionString)))
{
cmd.Parameters.Add(new MySqlParameter("#Id", Id));
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection.Open();
//CommandBehavior.CloseConnection
MySqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dataReader.Read())
{
result.Add(dataReader["name"].ToString(), dataReader["value"].ToString());
}
//dataReader.Close();
}
return result;
}
public void UpdateProductAttributesJsonField(int productId, string json)
{
using( MySqlCommand cmd = new MySqlCommand("UpdateArticleAttributes", new MySqlConnection(connection.ConnectionString)))
{
cmd.Parameters.Add(new MySqlParameter("#articleId", productId));
cmd.Parameters.Add(new MySqlParameter("#json", json));
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
//cmd.EndExecuteNonQuery(CommandBehavior.CloseConnection); // cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
Here is my initialize method
private void Initialize()
{
server = ConfigurationManager.AppSettings["ShopwareDBServer"];
database = ConfigurationManager.AppSettings["DatabaseName"];
uid = ConfigurationManager.AppSettings["DatabaseUser"];
password = ConfigurationManager.AppSettings["DatabasePassword"];
port = "3306";
string connectionString;
connectionString = "SERVER=" + server + ";" + "Port=" + port + ";" + "DATABASE=" +
database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";" + "Convert Zero Datetime=True";
connection = new MySqlConnection(connectionString);
}
I am getting this error :
{"error connecting: Timeout expired. The timeout period elapsed prior
to obtaining a connection from the pool. This may have occurred
because all pooled connections were in use and max pool size was
reached."}
Since you are using Data Reader in your code, you need to close the connection before opening a new one.
It may seem to be a suggestion rather than answering the question, but let me show you another way to do the same thing.
You want to call 3 procedures then why you are not combining these three procedures and create a new one in the database and call that procedure. I think, this way you need only one connection and your problem will be solved.
By the way, this is not possible to call three procedures on the same connection that uses "Data Reader".
You can check whether the connection state is opened or closed; this can help you decrease your maximum connection pool size.
You can write the code like this:
If(Connection.State == Closed) {
Connection.open
}
This is because you use maximum connection pool size may be in your code you no where write connection.close() so connection size is increase with time so just make sure you close connections in finally block.
First restart MySQL so it will close all the connection and change your code accordingly. And this issue is not due to calling 3 stored procedures in one connection and if you want to do it is done in multiple way.
Either you call one stored procedure and call other procedures from the first one.
You also call stored procedures step by step from c# code as well.

Need the result of a FoxPro RLOCK() command via OLEDbCommand

I'm trying to execute an RLOCK() command (record lock) on a FoxPro table via OleDbCommand but I need to know if the lock succeeded. In FoxPro, the RLOCK() returns .T. or .F. to indicate if it succeeded.
How do I get that result via OleDbCommand?
Here is my current code:
using(var conn = new OleDbConnection(...)) //connection string with VFPOLEDB provider
{
conn.Open();
using(var comm = new OleDbCommand())
{
string cText = #"[use table in 0] + chr(13) + "
+ #"[RLOCK(table)]";
comm.Connection = conn;
comm.CommandText = "Execute(" + cText + ")";
var result = comm.ExecuteNonQuery();
Consle.WriteLine(result);
comm.Dispose();
}
conn.Close();
conn.Dispose();
}
Right now, I'm always getting back a 1 (true) even when the Lock should not have taken place due to the fact that the record is already locked by someone else.
Thanks for your help.
Because you are not returning the result of the rlock() (and that you are using ExecuteNonQuery, when you should ask a return value and use ExecuteScalar instead). You would normally get back true with that code if you properly have used ExecuteScalar. In VFP each and every procedure returns .T. if no return value is specified (or call it a function if you will - in VFP procedure and function have no difference except name).
Here is a revised version of your code:
string myCode =
#"use c:\temp\lockTest
locked = rlock()
return m.locked
";
string strCon = #"Provider=VFPOLEDB;Data Source=c:\temp";
using (OleDbConnection con = new OleDbConnection(strCon))
{
OleDbCommand cmd = new OleDbCommand("ExecScript", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#code", myCode);
con.Open();
Console.WriteLine(cmd.ExecuteScalar());
con.Close();
}
While this code works perfectly well, I have no idea what you would do with a useless rlock() other than learning that you can't lock it due to some reason. In real life Execscript has little value.

ExecuteNonQuery requires an open available connection. The connection’s current state is closed

i want to check if the invoice number in invoices table if not exists then add new invoice number an fill invoice details in invoicedetails table, else if it is exists in invoices table just i want to update the Total field in case if the invoice has more than one item,
in the class:
StockClass stk = new StockClass();
stk.Quantity = txtQuantity.Text;
stk.StockID = txtStockID.Text;
stk.QtyUpdate();
MessageBox.Show("Stock record has been Successfully updated ");
InvoiceClass invclass = new InvoiceClass();
try
{
OleDbConnection myConnection = default(OleDbConnection);
myConnection = new OleDbConnection(cs);
OleDbCommand myCommand = default(OleDbCommand);
myCommand = new OleDbCommand("SELECT InvoiceNo FROM Invoices WHERE InvoiceNo = #InvoiceNo", myConnection);
OleDbParameter invono = new OleDbParameter("#username", OleDbType.VarChar);
invono.Value = txtInvoiceNo.Text;
myCommand.Parameters.Add(invono);
myCommand.Connection.Open();
OleDbDataReader myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
if (myReader.Read() == true)
{
invclass.InvoiceNo = txtInvoiceNo.Text;
invclass.Total = txtGrandTotal.Text;
invclass.Date = InvDate.Text;
invclass.updateinvoNumber();
}
else
{
invclass.InvoiceNo = txtInvoiceNo.Text;
invclass.Total = txtGrandTotal.Text;
invclass.Date = InvDate.Text;
invclass.AddNewinvoNumber();
invclass.InvoiceID = txtInvoiceNo.Text;
invclass.ProductID = txtProdID.Text;
invclass.ProName = txtProdName.Text;
invclass.ProType = txtProdType.Text;
invclass.ProSize = txtProdSize.Text;
invclass.Quantity = textQty.Text;
invclass.UnitPrice = txtPrice.Text;
invclass.Total = textTotal.Text;
invclass.Date = InvDate.Text;
invclass.CustName = txtCustName.Text;
invclass.EmpName = txtEmpName.Text;
invclass.AddNew();
}
if (myConnection.State == ConnectionState.Open)
{
myConnection.Dispose();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
OleDbDataAdapter ad = new OleDbDataAdapter("Select ProName, ProType, ProSize, Quantity, UnitPrice, Total, CustName, EmpName, date From InvoiceDetails WHERE [InvoiceID] = ?", cs);
ad.SelectCommand.Parameters.Add("#InvoiceID", OleDbType.VarChar);
ad.SelectCommand.Parameters["#InvoiceID"].Value = txtInvoiceNo.Text;
DataSet ds = new DataSet();
ad.Fill(ds, "Invo");
DGV1.DataSource = ds.Tables["Invo"];
DGV1.DataSource = ds.Tables[0];
}
When it is not exist it is working good, but when its exist i am facing an error
ExecuteNonQuery requires an open available connection. The connection’s current state is closed
public void updateinvoNumber()
{
using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|StoreSys.mdb"))
using (OleDbCommand cmd = new OleDbCommand("UPDATE [invoices] SET [InvoiceNo]=?, [Total] = ?,[Date] = ? WHERE [InvoiceNo] = ?", conn))
{
cmd.Parameters.AddWithValue("p0", InvoiceNo);
cmd.Parameters.AddWithValue("p1", Total);
cmd.Parameters.AddWithValue("p2", Date);
cmd.ExecuteNonQuery();
conn.Close();
}
}
I guess I should post this as an answer...
You are not opening your connection, plain and simple.
Instead of...
using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|StoreSys.mdb"))
using (OleDbCommand cmd = new OleDbCommand("UPDATE [invoices] SET [InvoiceNo]=?, [Total] = ?,[Date] = ? WHERE [InvoiceNo] = ?", conn))
{
cmd.Parameters.AddWithValue("p0", InvoiceNo);
cmd.Parameters.AddWithValue("p1", Total);
cmd.Parameters.AddWithValue("p2", Date);
cmd.ExecuteNonQuery();
conn.Close();
}
You need... (notice the conn.Open();)
using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|StoreSys.mdb"))
{
conn.Open(); // <-- You forgot this.
using (OleDbCommand cmd = new OleDbCommand("UPDATE [invoices] SET [InvoiceNo]=?, [Total] = ?,[Date] = ? WHERE [InvoiceNo] = ?", conn))
{
cmd.Parameters.AddWithValue("p0", InvoiceNo);
cmd.Parameters.AddWithValue("p1", Total);
cmd.Parameters.AddWithValue("p2", Date);
cmd.ExecuteNonQuery();
// conn.Close(); <-- you don't need this btw. This will happen automatically as you exit the "using" block.
}
}
Okay, I see the problem. The problem is perfectly described in the error message: you don't have a connection open.
You do it up top with the myCommand object: myCommand.Connection.Open();
However with the OleDbDataAdapter object named 'ad', even thought you specify a connection string, you have to explicitly open the connection.
I just visited Microsofts page for the OleDbDataAdapter constructor overload you are using (the one with two strings) located at https://msdn.microsoft.com/en-us/library/2f8y4737.aspx and it had this to say, under the remarks section.
This overload of the OleDbDataAdapter constructor uses the selectConnectionString parameter to set the SelectCommand property. However, it does not open the connection. You still must explicitly open the connection.
Looking at your code, I believe the smallest change you can do to accomplish this would be to add the code:
ad.SelectCommand.Connection.Open();
in between setting the SqlParameters and filling the DataSet:
ad.SelectCommand.Parameters["#InvoiceID"].Value = txtInvoiceNo.Text;
**ad.SelectCommand.Connection.Open();** // <- HERE
DataSet ds = new DataSet();
ad.Fill(ds, "Invo");
However, I'm not 100% sure that that will work as shown, as I've never opened a connection in this way, I usually explicitly create an a connection object, and open it before even setting the command. Also, you are going to want to use 'using' statements to ensure the database connection gets closed and disposed, otherwise you will leave a connection open with the SQL server, and there are only limited number of those. I have seen applications that borf the server by creating and failing to close too many connections in a short time.
So if the code ad.SelectCommand.Connection.Open(); does not work, try creating the connection object explicitly like you do above, and then you can set associate the connection object with the OleDbDataAdapter in its constructor in place of the connection string:
using(OleDbConnection myConnection2 = new OleDbConnection(cs))
{
myConnection2.Open();
using(OleDbDataAdapter ad = new OleDbDataAdapter(/*truncated*/, myConnection2))
{
[...]

ASP.Net C# - Passing a variable into MySQL query

So I want to create a line graph with data from a MySQL table and I've managed to draw one using the code below.
However, I want to pass a variable 'moduleID' to the MySQL query and I have done so, however, I'm not sure if this is the most appropriate way to do so. Should I pass a parameter instead and if so, how do I do that?
protected void chart(int moduleID)
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
string comm = "SELECT * FROM scores WHERE module_id=" + moduleID.ToString();
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(comm, conn);
DataSet ds = new DataSet();
Chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Minimum = 1;
Chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Title = "time";
Chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 0;
Chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 100;
Chart1.ChartAreas["ChartArea1"].AxisY.Title = "%";
Chart1.ChartAreas["ChartArea1"].AxisY.TextOrientation = TextOrientation.Horizontal;
try
{
conn.Open();
dataAdapter.Fill(ds);
Chart1.DataSource = ds;
Chart1.Series["Series1"].YValueMembers = "score";
Chart1.DataBind();
}
catch
{
lblError.Text = "Database connection error. Unable to obtain data at the moment.";
}
finally
{
conn.Close();
}
}
You are right. Concatenating strings to form a query is prone to SQL injection. Use parameters like:
string comm = "SELECT * FROM scores WHERE module_id=#module_id";
MySqlCommand mySqlCommand = new MySqlCommand(comm,conn);
mySqlCommand.Parameters.Add(new MySqlParameter("#module_id", module_id));
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(mySqlCommand);
You should also enclose your connection and command object with using statement. This will ensure proper disposal of resource.
Also an empty catch is very rarely useful. You should catch specific exception first and then the base exception Exception in an object. Use that object to log the exception information or show in your error message. This will provide you help in debugging your application.
Step1: Create stored Procedure
CREATE PROCEDURE SelectScore
(#moduleID NCHAR(50))AS
SELECT * FROM scores WHERE module_id=#moduleID
Step2: Call the stored Procedure from Code
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr )) {
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("SelectScore", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("#moduleID ", moduleID ));
// execute the command
using (SqlDataReader rdr = cmd.ExecuteReader()) {
// iterate through results, printing each to console
while (rdr.Read())
{
..
}
}
}

the perfect way to connect to database?

public class SqlHelper
{
public SqlHelper()
{
}
public static SqlConnection GetConnection()
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = #"Data Source=.\SQLEXPRESS;AttachDbFilename=" + System.Web.HttpContext.Current.Server.MapPath(#"~\App_Data\learn.mdf") + ";Integrated Security=True;User Instance=True";
return conn;
}
public static SqlDataReader ExecuteReader(string sql)
{
SqlConnection con = GetConnection();
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader dr = null;
try
{
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch
{
con.Close();
return null;
}
return dr;
}
public static Object ExecuteScalar(string sql)
{
SqlConnection con = GetConnection();
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
Object val = null;
try
{
val = cmd.ExecuteScalar();
}
catch
{
con.Close();
return null;
}
finally
{
con.Close();
}
return val;
}
public static DataSet ExecuteDataSet(string sql)
{
SqlConnection con = GetConnection();
SqlCommand cmd = new SqlCommand(sql, con);
DataSet ds = new DataSet();
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
try
{
adapt.Fill(ds);
}
catch
{
con.Close();
}
return ds;
}
public static void ExecuteNonQuery(string sql)
{
SqlConnection con = GetConnection();
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
try
{
cmd.ExecuteNonQuery();
}
finally
{
con.Close();
}
}
}
This is the Class which I use to implement every access to my database . But I think that the way I do connection with the database is a little bit overblown cause I have to hit the Connect function every time I need something . As well as other users going to do the same which kills the performance.
So what is the perfect way to connect with the database - and to stay connected if that better . Note that I use the database in many pages!
Thanks
First, you should be using "using" statements to ensure that all your ADO.NET objects are properly disposed of in the event of a failure:
public static void ExecuteNonQuery(string sql)
{
using(var con = GetConnection())
{
con.Open();
using(var cmd = new SqlCommand(sql, con))
{
cmd.ExecuteNonQuery();
}
}
}
However, having said that, I don't really see a problem with this approach. The advantage is that the connections, commands, adapters and whatnot are properly disposed of every time you execute a bit of SQL. If you were to make a single static SqlConnection instance, you'd escalate the chances that the connection is already in use (when, for example, iterating over the contents of a SqlDataReader).
If you are really concerned about it, provide overloads that take a connection as an extra parameter:
public static void ExecuteNonQuery(string sql, SqlConnection connection)
{
using(var cmd = new SqlCommand(sql, con))
{
cmd.ExecuteNonQuery();
}
}
This way, callers can either execute a bit of SQL that doesn't require multiple calls, or they can call your GetConnectionMethod to obtain a connection, and pass it to multiple calls.
If this is used for a web site then you have to consider that between requests for pages, even from the same browser, your server state will be torn down (in general terms) so there's nothing really to be gained from trying to maintain your SQL connection between pages. That's the first thing.
If each page is the result of a single database connection then you are probably as optimised as you really need to be, if you are making several connections over the generation of a page then you may want to look at keeping a connection alive until you have finished retrieving data; either by maintaining the connection or optimising your data retrieval to limit the back and forth between your app and the db.
Maintaining a database connection is the job of the connection pool, and not the connection consumer. The best practice is to aquire a connection as late as possible and release it as soon as possible.
using(var connection = new SqlConnection(YourConnectionStringHelperFunction())
{
}
One thing that YOu might take into consideration is the Dependency Injection PAttern and some IoC controller. If every page needs to have this connection make this an injectable property (constructor probably wont work unless You implement some kind of infrastructure classes like Request) use some container (Unity, Castle, StructureMap) pack the needed things up (maybe cache, maybe some other things) and let the container do the magic (by magic I mean tons of boilerplate code) for You.
luke
First you can write a seperate class like this :
Get method for getting data (with a Select query) and Set method for manipulating data (Insert, Update, Delete)
using System.Data;
using System.Data.Odbc;
using System.Data.SqlClient; //using this you can replace instead odbc to sql
// Example SqlCommand, SqlDataAdapter
class DataBaseConnection
{
private OdbcConnection conn1 = new OdbcConnection(#"FILEDSN=C:/OTPub/Ot.dsn;" + "Uid=sa;" + "Pwd=otdata#123;"); //"DSN=Ot_DataODBC;" + "Uid=sa;" + "Pwd=otdata#123;"
//insert,update,delete
public int SetData(string query)
{
try
{
conn1.Open();
OdbcCommand command = new OdbcCommand(query, conn1);
int rs = command.ExecuteNonQuery();
conn1.Close();
return rs;
}
catch (Exception ex)
{
conn1.Close();
throw ex;
}
}
//select
public System.Data.DataTable GetData(string sql)
{
try
{
conn1.Open();
OdbcDataAdapter adpt = new OdbcDataAdapter(sql, conn1);
DataTable dt = new DataTable();
adpt.Fill(dt);
conn1.Close();
return dt;
}
catch (Exception ex)
{
conn1.Close();
throw ex;
}
}
}
in your form you can make object to that database connection class
DataBaseConnection db = new DataBaseConnection();
now you cal call get set with your get set method as following
string sqlSpecialHoliyday = "SELECT * FROM Holiday WHERE Date_Time='" + selectdate + "' AND IDH='50'";
DataTable dtAdditionalholily = db.GetData(sqlSpecialHoliyday);
AD you can Set Data Using Set method
string insertloginlog = "INSERT INTO Login_Log (Service_No, Machine_Name) VALUES ('" + serviceID + "','" + machiname + "')";
int ret = db.SetData(insertloginlog);
Hope This will help!

Categories