I've got the following code (here with pseudovalues for readability), where the first connection returns a lot of data (thousands of rows). SqlDataReader reads them one by one by the reader.Read() and then opens a new connection to update each row with new values:
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand cmd = new SqlCommand("sp1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#param1", param1);
cmd.Connection.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
try
{
string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue);
using (SqlConnection conn2 = new SqlConnection(connString))
using (SqlCommand cmd2 = new SqlCommand("sp2", conn2))
{
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Parameters.AddWithValue("#param1", param1);
cmd2.Parameters.AddWithValue("#param2", param2);
cmd2.Connection.Open();
cmd2.ExecuteNonQuery();
}
}
catch (SqlException ex)
{
//something
}
}
}
}
but it throws an error:
[InvalidOperationException: Invalid attempt to call Read when reader is closed.]
System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) +640
System.Data.SqlClient.SqlDataReader.Read() +9
In development environment it works fine, but here there's only a few hundred rows. It throws the error immediately, so it doesn't directly look like some kind of timeout, but hey - I don't know...
Don't know why it happens, but it's really a bad idea to execute queries while iterating a live connection to the same database. Keep in mind that as long as you iterate records with a DataReader, the connection is alive.
Much worse is opening then closing a connection thousands of times in a quick succession. This alone can bring any database down to its knees.
Change your logic, store the values you need in a local variable (structure doesn't matter) then use one connection only to execute all the stored procedures you need.
For example:
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
List<string[]> values = new List<string[]>();
using (SqlCommand cmd = new SqlCommand("sp1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#param1", param1);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
try
{
string hash= utils.SHA256.Hashing((string)reader["firstRow"], saltValue);
string anotherValue = (string)reader["secondRow"];
values.Add(new string[] { hash, anotherValue });
}
catch (SqlException ex)
{
//something
}
}
reader.Close();
}
}
if (values.Count > 0)
{
using (SqlCommand cmd2 = new SqlCommand("sp2", conn))
{
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Parameters.AddWithValue("#param1", null);
cmd2.Parameters.AddWithValue("#param2", null);
values.ForEach(items =>
{
cmd2.Parameters["#param1"].Value = items[0];
cmd2.Parameters["#param2"].Value = items[1];
cmd2.ExecuteNonQuery();
});
}
}
conn.Close();
}
One connection, one command to execute all stored procedures. Really don't need more than that.
Related
How can I implement a simple cursor fetch on a basic SELECT statement like 'SELECT * FROM Employees' using ODP.NET?
So it's quite straightforward.
First create OracleConnection class like this
OracleConnection con = new OracleConnection(ConfigurationManager.ConnectionStrings["connectionstring"].ConnectionString);
con.Open(); //opens connection
Then you define and OracleCommand instance first by passing either raw query/stored procedure as first argument like
So in your particular case it would be OracleCommand cmd = new OracleCommand("SELECT * FROM Employees", con
if (con.State == ConnectionState.Open)
{
using (OracleCommand cmd = new OracleCommand(<query>/<stored proc>, con))
{
cmd.CommandType = CommandType.StoredProcedure; //in case of stored proc
cmd.BindByName = true;
OracleDataReader reader;
try
{
reader = cmd.ExecuteReader();
while(reader.Read())
{
Console.WriteLine("field: {0}", reader.GetDecimal(0));
}
}
catch (OracleException e)
{
foreach (OracleError err in e.Errors)
{
//print errors
}
}
con.Close();
con.Dispose();
}
}
Here is the example http://www.oracle.com/technetwork/articles/dotnet/williams-refcursors-092375.html
I'm trying to get the SQL result in a C# string variable or string array. Is it possible? Do I need to use SqlDataReader in some way?
I'm very new to C# functions and all, used to work in PHP, so please give a working example if you can (If relevant I can already connect and access the database, insert and select.. I just don't know how to store the result in a string variable).
This isn't the single greatest example in history, as if you don't return any rows from the database you'll end up with an exception, but if you want to use a stored procedure from the database, rather than running a SELECT statement straight from your code, then this will allow you to return a string:
public string StringFromDatabase()
{
SqlConnection connection = null;
try
{
var dataSet = new DataSet();
connection = new SqlConnection("Your Connection String Goes Here");
connection.Open();
var command = new SqlCommand("Your Stored Procedure Name Goes Here", connection)
{
CommandType = CommandType.StoredProcedure
};
var dataAdapter = new SqlDataAdapter { SelectCommand = command };
dataAdapter.Fill(dataSet);
return dataSet.Tables[0].Rows[0]["Item"].ToString();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
finally
{
if (connection != null)
{
connection.Close();
}
}
}
It can definitely be improved, but it would give you a starting point to work from if you want to go down a stored procedure route.
Try This:
SqlConnection con=new SqlConnection("/*connection string*/");
SqlCommand SelectCommand = new SqlCommand("SELECT email FROM table1", con);
SqlDataReader myreader;
con.Open();
myreader = SelectCommand.ExecuteReader();
List<String> lstEmails=new List<String>();
while (myreader.Read())
{
lstEmails.Add(myreader[0].ToString());
//strValue=myreader["email"].ToString();
//strValue=myreader.GetString(0);
}
con.Close();
accessing the Emails from list
lstEmails[0]->first email
lstEmails[1]->second email
...etc.,
You could use an SQL Data Reader:
string sql = "SELECT email FROM Table WHERE Field = #Parameter";
string variable;
using (var connection = new SqlConnection("Your Connection String"))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Parameter", someValue);
connection.Open();
using (var reader = command.ExecuteReader())
{
//Check the reader has data:
if (reader.Read())
{
variable = reader.GetString(reader.GetOrdinal("Column"));
}
// If you need to use all rows returned use a loop:
while (reader.Read())
{
// Do something
}
}
}
Or you could use SqlCommand.ExecuteScalar()
string sql = "SELECT email FROM Table WHERE Field = #Parameter";
string variable;
using (var connection = new SqlConnection("Your Connection String"))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Parameter", someValue);
connection.Open();
variable = (string)command.ExecuteScalar();
}
This May help you For MySQL
MySqlDataReader reader = mycommand.ExecuteReader();
while (reader.Read())
{
TextBox2.Text = reader.ToString();
}
For SQL
using (SqlCommand command = new SqlCommand("*SELECT QUERY HERE*", connection))
{
//
// Invoke ExecuteReader method.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
TextBox2.Text = reader.GetString(0);
}
}
Try this:
public string SaveStringSQL(string pQuery, string ConnectionString)
{
var connection = new Conexao(ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand(pQuery, connection.Connection);
var SavedString = (string)command.ExecuteScalar();
connection.Close();
return SavedString;
}
The ExecuteScalar function saves whatever type of data there is on your database - you just have to specify it.
Keep in mind that it can only save one line at a time.
I'm curious as to why this is. I ran into this scenario earlier today
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
}
}
//Get the new set of ExpenseCycles for binding
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
// ^^ this works just fine. The GetExpenseCycles call will basically set up the structure above with using SqlConnection and using SqlCommand
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
//Get the new set of ExpenseCycles for binding
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
//This didn't work. The INSERT statement was successful, but it was bringing back old entries, and did not include the newest one that was just inserted
}
}
The bottom code block was initially what I had, and the return count for my test environment was only 1, but there were 2 records in the database. It wasn't fetching that newly inserted record.
The basic code of GetExpenseCycles is the following:
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_GetExpenseCyclesByPortal",oConn))
{
oConn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
//Read List<expensecycle> here
}
}
}
Any ideas why? There were no exceptions thrown.
No exceptions thrown so no errors... I suspect the isolation-level on the connection
In the first scenario the connections don't overlap.
ExpenseCycle() use a connection string and I may safely assume it starts a new connection.
In the second example (problem case) the connections do overlap:
If the isolation-level is for instance read-committed and the "enclosing" connection hasn't yet stabilized its write (commit) the new connection don't pick up the changes, in this case the insert.
Possible solutions or things to try out:
1. Check the isolation-level on the connection
2. Pass the connection instead of the connectionstring to ExpenseCycle() (which is a better practice too imho)
You might have an ambient transaction in effect (if the code block is called within the scope of a transaction, new connections will join that transaction automatically. Using the TransactionScope class, you can get a handle of that transaction and commit it before the second call.
Also it looks like your second call is within the scope of the command's using block. Moving it outside of there might be enough to resolve your problem
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw ex;
}
}//close the SqlCommand
//Get the new set of ExpenseCycles for binding
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
//This might fix your problem.
}
The other option is to move the second call outside the using of the first using block like so
bool insertSuccessful;
using (SqlConnection oConn = new SqlConnection(ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("IC_Expense_InsertCycle", oConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#PortalId", portalId);
cmd.Parameters.AddWithValue("#Description", description);
cmd.Parameters.AddWithValue("#StartDate", start);
cmd.Parameters.AddWithValue("#EndDate", end);
try
{
oConn.Open();
cmd.ExecuteNonQuery();
insertSuccessful=true;
}
catch (SqlException ex)
{
insertSuccessful=false
throw ex;
}
}//close the SqlCommand
}//close the connection
//Get the new set of ExpenseCycles for binding
if(insertSuccessful)
{
ExpenseCycle cycle = new ExpenseCycle(ConnectionString);
return cycle.GetExpenseCycles(portalId);
}
I think the first block should fix your problem. If not the second one definitely should.
First question:
Say I have
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
Does the connection get closed? Because technically we never get to the last } as we return before it.
Second question:
This time I have:
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
int employeeID = findEmployeeID();
connection.Open();
SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
}
catch (Exception) { /*Handle error*/ }
Now, say somewhere in the try we get an error and it gets caught. Does the connection still get closed? Because again, we skip the rest of the code in the try and go directly to the catch statement.
Am I thinking too linearly in how using works? ie Does Dispose() simply get called when we leave the using scope?
Yes
Yes.
Either way, when the using block is exited (either by successful completion or by error) it is closed.
Although I think it would be better to organize like this because it's a lot easier to see what is going to happen, even for the new maintenance programmer who will support it later:
using (SqlConnection connection = new SqlConnection(connectionString))
{
int employeeID = findEmployeeID();
try
{
connection.Open();
SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
catch (Exception)
{
/*Handle error*/
}
}
Yes to both questions. The using statement gets compiled into a try/finally block
using (SqlConnection connection = new SqlConnection(connectionString))
{
}
is the same as
SqlConnection connection = null;
try
{
connection = new SqlConnection(connectionString);
}
finally
{
if(connection != null)
((IDisposable)connection).Dispose();
}
Edit: Fixing the cast to Disposable
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
Here is my Template. Everything you need to select data from an SQL server. Connection is closed and disposed and errors in connection and execution are caught.
string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = #"
SELECT TOP 1 Person
FROM CorporateOffice
WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand comm = new SqlCommand(selectStatement, conn))
{
try
{
conn.Open();
using (SqlDataReader dr = comm.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
Console.WriteLine(dr["Person"].ToString());
}
}
else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
}
}
catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
if (conn.State == System.Data.ConnectionState.Open) conn.Close();
}
}
* Revised: 2015-11-09 *
As suggested by NickG; If too many braces are annoying you, format like this...
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand comm = new SqlCommand(selectStatement, conn))
{
try
{
conn.Open();
using (SqlDataReader dr = comm.ExecuteReader())
if (dr.HasRows)
while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
}
catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
if (conn.State == System.Data.ConnectionState.Open) conn.Close();
}
Then again, if you work for EA or DayBreak games, you can just forgo any line-breaks as well because those are just for people who have to come back and look at your code later and who really cares? Am I right? I mean 1 line instead of 23 means I'm a better programmer, right?
using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }
Phew... OK. I got that out of my system and am done amusing myself for a while. Carry on.
Dispose simply gets called when you leave the scope of using. The intention of "using" is to give developers a guaranteed way to make sure that resources get disposed.
From MSDN:
A using statement can be exited either when the end of the using statement is reached or if an exception is thrown and control leaves the statement block before the end of the statement.
Using generates a try / finally around the object being allocated and calls Dispose() for you.
It saves you the hassle of manually creating the try / finally block and calling Dispose()
In your first example, the C# compiler will actually translate the using statement to the following:
SqlConnection connection = new SqlConnection(connectionString));
try
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
finally
{
connection.Dispose();
}
Finally statements will always get called before a function returns and so the connection will be always closed/disposed.
So, in your second example the code will be compiled to the following:
try
{
try
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
finally
{
connection.Dispose();
}
}
catch (Exception)
{
}
The exception will be caught in the finally statement and the connection closed. The exception will not be seen by the outer catch clause.
I wrote two using statements inside a try/catch block and I could see the exception was being caught the same way if it's placed within the inner using statement just as ShaneLS example.
try
{
using (var con = new SqlConnection(#"Data Source=..."))
{
var cad = "INSERT INTO table VALUES (#r1,#r2,#r3)";
using (var insertCommand = new SqlCommand(cad, con))
{
insertCommand.Parameters.AddWithValue("#r1", atxt);
insertCommand.Parameters.AddWithValue("#r2", btxt);
insertCommand.Parameters.AddWithValue("#r3", ctxt);
con.Open();
insertCommand.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
No matter where's the try/catch placed, the exception will be caught without issues.
Old thread but still relevant. I arrived here looking for a way out of having a using statement inside of a using statement. I am happy with this, notwithstanding any future insightful comments that change my mind. ;) Conversations here helped. Thanks. Simplified for readability -
public DataTable GetExchangeRates()
{
DataTable dt = new DataTable();
try
{
logger.LogInformation($"Log a message.");
string conStr = _config.GetConnectionString("conStr");
using (SqlCommand cmd = new SqlCommand("someProc", new SqlConnection(conStr)))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection.Open();
dt.Load(cmd.ExecuteReader());
}
return dt;
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
}
}
This is a really, really stupid question but I am so accustomed to using linq / other methods for connecting and querying a database that I never stopped to learn how to do it from the ground up.
Question: How do I establish a manual connection to a database and pass it a string param in C#? (yes, I know.. pure ignorance).
Thanks
using (SqlConnection conn = new SqlConnection(databaseConnectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "StoredProcedureName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID", fileID);
conn.Open();
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (rdr.Read())
{
// process row from resultset;
}
}
}
}
One uses the SqlCommand class to execute commands (either stored procedures or sql) on SQL Server using ado.net. Tutorials abound.
Here's an example from http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson07.aspx
public void RunStoredProcParams()
{
SqlConnection conn = null;
SqlDataReader rdr = null;
// typically obtained from user
// input, but we take a short cut
string custId = "FURIB";
Console.WriteLine("\nCustomer Order History:\n");
try
{
// create and open a connection object
conn = new
SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI");
conn.Open();
// 1. create a command object identifying
// the stored procedure
SqlCommand cmd = new SqlCommand(
"CustOrderHist", 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("#CustomerID", custId));
// execute the command
rdr = cmd.ExecuteReader();
// iterate through results, printing each to console
while (rdr.Read())
{
Console.WriteLine(
"Product: {0,-35} Total: {1,2}",
rdr["ProductName"],
rdr["Total"]);
}
}
finally
{
if (conn != null)
{
conn.Close();
}
if (rdr != null)
{
rdr.Close();
}
}
}
3 things no one else has shown you yet:
"Stacking" using statements
Setting an explicit parameter type rather than letting .Net try to pick one for you
"var" keyword
.
string sql = "MyProcedureName";
using (var cn = new SqlConnection(databaseConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ParameterName", SqlDbType.VarChar, 50)
.Value = "MyParameterValue";
conn.Open();
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (rdr.Read())
{
// process row from resultset;
}
}
}