i am trying to get used to working with "using" blocks in C#, but i'm having a hard time understanding when i should be using them.
here is an example.
my original code, without the using block:
SqlConnection conn = new SqlConnection(cCon.getConn());
SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{ }
finally
{
conn.Close();
}
but should i really be doing this? or should i be using(SqlConnection conn = new SqlConnection(cCon.getConn())) ? please help me understand this. is the way i'm originally doing it so wrong?
SqlConnection conn = new SqlConnection(cCon.getConn());
using( SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{ }
finally
{
conn.Close();
}
}
but i'm having a hard time understanding when i should be using them.
It's easy. Everytime you are dealing with a class that implements the IDisposable interface you should use them. Just like this:
using (SqlConnection conn = new SqlConnection(cCon.getConn()))
using (SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "sp_SaveSomething";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
cmd.ExecuteNonQuery();
}
and if you wanna handle some exceptions you could wrap the code you wanna handle in a try/catch statement:
try
{
using (SqlConnection conn = new SqlConnection(cCon.getConn()))
using (SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "sp_SaveSomething";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// do something here with the exception, don't just consume it,
// otherwise it's meaningless to catch it
}
As you can see all IDisposable resources (SqlConnection and SqlCommand in this code snippet) are now properly wrapped in using statements which guarantees that they will be properly disposed even if an exception is thrown. As a consequence you no longer need to be using a finally statement and explicitly doing this.
Also remember that ADO.NET uses a connection pool meaning that when you are calling the .Open() method on a SqlConnection you are not opening a physical connection to the database. You are simply drawing one from the pool. And when you call the .Close (or .Dispose) method you are not closing the connection. You are simply returning it to the connection pool so that it can be reused.
You wouldn't have to close the connection if you put it into using blocks. Using blocks are used for objects that implement IDisposable. IDisposable allows an object to clear unmanaged resources before being collected by the GC. This frees up memory and allows the GC to collect that object.
A using block is just a try/finally clause with automatic closing and disposing of disposable objects. Adding an internal try/catch serves only if you plan to handle in some way the exception thrown. In your example you do nothing in the catch block, so it is unnecessary.
Both the SqlCommand and SqlConnection are disposable so your code should be changed to
using(SqlConnection conn = new SqlConnection(cCon.getConn())
using( SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
conn.Open();
cmd.ExecuteNonQuery();
}
You should have a couple of using blocks here, actually, since SqlConnection and SqlCommand both implement IDisposable. And the using also takes care of closing the connection at the end, so the explicit conn.Close(); becomes unnecessary.
using (SqlConnection conn = new SqlConnection(cCon.getConn()))
using (SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
// Log error, etc.
}
}
It will go this way:
using (SqlConnection conn = new SqlConnection(cCon.getConn()))
{
using (SqlCommand cmd = new SqlCommand("sp_SaveSomething", conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#x", xxx));
cmd.Parameters.Add(new SqlParameter("#ORG", ORG));
cmd.ExecuteNonQuery();
}
}
As SqlConnection and SqlCommand implements the IDisposable interface, the using block will deal with the Close and Dispose methods.
Related
Is there a way to add OPTION (RECOMPILE) in C# while executing stored procedure by System.Data.SqlClient?
What I'm looking for in my imagination would be something like
using (SqlConnection sqlConn = new SqlConnection(CONN_STR))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand("usp_xyz OPTION (RECOMPILE)", sqlConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("x", x);
cmd.ExecuteNonQuery();
}
}
Yes, you can use the EXEC... WITH RECOMPILE syntax, but you must do it as an ad-hoc batch, and therefore specify all parameters. You cannot use this with CommandType.StoredProcedure.
using (SqlConnection sqlConn = new SqlConnection(CONN_STR))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand("EXEC usp_xyz #x = #x WITH RECOMPILE;", sqlConn))
{
cmd.Parameters.Add("#x", SqlDbType.SomeType, SomeLength).Value = x;
cmd.ExecuteNonQuery();
}
}
If you want, you could use sp_recompile, but this has different semantics: it does not just generate a new plan for this run, it discards the old plan for all future runs of the procedure.
using (SqlConnection sqlConn = new SqlConnection(CONN_STR))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand("sp_recompile", sqlConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#objname", SqlDbType.NVarChar, 776).Value = "dbo.usp_xyz";
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd = new SqlCommand("usp_xyz", sqlConn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#x", SqlDbType.SomeType, SomeLength).Value = x;
cmd.ExecuteNonQuery();
}
}
I have a problem in SqlDataReader - it cannot proceed into while and cannot while.
Here is my code
List<tmp_WatchList> data = new List<tmp_WatchList>();
using (SqlConnection con = new SqlConnection(conStr))
{
using (SqlCommand cmd = new SqlCommand("sp_CheckPersonList", con))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
SqlDataReader oReader = cmd.ExecuteReader();
while (oReader.Read())
{
//data.Add(new tmp_WatchList
//{
tmp_WatchList l = new tmp_WatchList();
l.id = int.Parse(oReader["id"].ToString());
l.Name = oReader.GetValue(1).ToString();
l.Crime = int.Parse(oReader.GetValue(2).ToString());
data.Add(l);
///});
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
con.Close();
}
}
}
and my stored procedure is:
ALTER PROCEDURE [dbo].[sp_CheckPersonList]
(#Name NVARCHAR(MAX) NULL)
AS
BEGIN
SELECT REPLACE(Name, '.', ''), Crime
FROM [dbo].[tmp_WatchList]
WHERE [Name] LIKE CONCAT('%', REPLACE(#Name, ' ', '%'), '%')
END
Can you tell me how it is done? Or is something wrong with my structure?
You are not opening the connection any where before calling the ExecuteReader, you need to open the database connection, following is the lineo of code to open the connection :
con.Open(); // open connection
SqlDataReader oReader = cmd.ExecuteReader(); // now execute SP
and you do not need finally block for closing the connection, as you are already applyuing the using block on your SqlConnection and SqlCommand which is converted by compiler in to try finally which takes care of disposing the resources and in case of SqlConnection closing the connection.
As other have pointed out, you need to Open the connection, and you can simplify your code removing the try/catch/finally and the explicit con.Close(), which you don't need since you are (corretcly) wrapping the connection within a using
Your code should be something like this (much cleaner than the original one after removing the try/catch/finally):
List<tmp_WatchList> data = new List<tmp_WatchList>();
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("sp_CheckPersonList", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
SqlDataReader oReader = cmd.ExecuteReader();
while (oReader.Read())
{
tmp_WatchList l = new tmp_WatchList();
l.id = int.Parse(oReader["id"].ToString());
l.Name = oReader.GetValue(1).ToString();
l.Crime = int.Parse(oReader.GetValue(2).ToString());
data.Add(l);
}
}
}
If that code raises an exception, it will simply be forwarded to the caller, in a better way comparing to what you did with your throw new Exception(exc.Message), which will loose the original stack trace
Remove the unwanted code..Try Like this..
List<tmp_WatchList> data = new List<tmp_WatchList>();
SqlConnection con = new SqlConnection(conStr);
SqlCommand cmd=new SqlCommand();
cmd.CommmandText="sp_CheckPersonList";
cmd.CommandType = CommandType.Text;
con.Open();
cmd.Connection = con;
cmd.Parameters.AddWithValue("#Name",name);
SqlDataReader oReader = cmd.ExecuteReader();
while (oReader.Read())
{
tmp_WatchList l = new tmp_WatchList();
l.id = int.Parse(oReader["id"].ToString());
l.Name = oReader.GetValue(1).ToString();
l.Crime = int.Parse(oReader.GetValue(2).ToString());
data.Add(l);
}
oReader.Close();
Con.Close();
I am trying to run a test query using sql. I know it is a simple concept, but i have tried everything I could find online and the following does not even run. It shows no errors but it does not run.
private static SqlConnection conn = new SqlConnection("<connection string>");
public static void connect()
{
conn.Open();
SqlCommand command = new SqlCommand("spTester 'this is tested'", conn);
command.ExecuteScalar();
conn.Close();
}
It seems that you want something like that:
private static void connect() {
// static SqlConnection conn is a bad idea, local variable is much better
// Do not forget to dispose IDisposable: using(...) {...}
using (SqlConnection conn = new SqlConnection("<connection string>")) {
// Do not forget to dispose IDisposable: using(...) {...}
using (SqlCommand command = new SqlCommand("spTester", conn)) {
// You're executing procedure, not ordinal SQL
command.CommandType = CommandType.StoredProcedure;
// It seems, that you should provide a parameter to your procedure:
//TODO: Change "#ParameterName" to actual one
command.Parameters.Add(new SqlParameter("#ParameterName", "this is tested"));
// You don't need any result value be returned
command.ExecuteNonQuery();
}
}
}
public static void connect()
{
conn.Open();
SqlCommand command = new SqlCommand("spTester 'this is tested'", conn);
command.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter(cmd);
conn.Close();
}
try doing this..
as u probably forgot to mention command.CommandType = CommandType.StoredProcedure; line
this is a simple example it will let you get started using SQLCOMMAND
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand("SELECT * FROM whatever
WHERE id = 5", conn);
try
{
conn.Open();
newID = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Try this :
public static void connect()
{
conn.Open();
SqlCommand command = new SqlCommand("spTester", conn);
command.CommandType = CommandType.StoredProcedure;
command.AddWithValue("#Parameter1","this is tested")
SqlDataAdapter da = new SqlDataAdapter(cmd);
conn.Close();
}
I created the below method which i tested and does return the correct data. Where I am confused is what is the proper way to populate individual textboxes on a form with the results from this method?
Rather than using an objectdatasource and then binding a gridview to the objectdatasource that works but I need more freedom to customize the form.
public MemberDetails GetMemberDetail(int membershipgen)
{
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("usp_getmemberdetail", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#MEMBERSHIPGEN", SqlDbType.Int, 5));
cmd.Parameters["#MEMBERSHIPGEN"].Value = membershipgen;
try
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
reader.Read();
MemberDetails mem = new MemberDetails((int)reader["MEMBERSHIPGEN"], (string)reader["MEMBERSHIPID"], (string)reader["LASTNAME"],
(string)reader["FIRSTNAME"], (string)reader["SUFFIX"], (string)reader["MEMBERTYPESCODE"]);
reader.Close();
return mem;
}
catch (SqlException err)
{
throw new ApplicationException("Data error.");
}
finally
{
con.Close();
}
Something along the lines of:
var memberDetails = GetMemberDetail(12345);
textBox1.Text = memberDetails.Prop1;
textBox2.Text = memberDetails.Prop2;
...
Also I would refactor this method and make sure that I properly dispose disposable resources by wrapping them in using statements to avoid leaking unmanaged handles:
public MemberDetails GetMemberDetail(int membershipgen)
{
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = con.CreateCommand())
{
con.Open();
cmd.CommandText = "usp_getmemberdetail";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#MEMBERSHIPGEN", membershipgen);
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if (reader.Read())
{
return new MemberDetails(
reader.GetInt32(reader.GetOrdinal("MEMBERSHIPGEN")),
reader.GetString(reader.GetOrdinal("MEMBERSHIPID")),
reader.GetString(reader.GetOrdinal("LASTNAME")),
reader.GetString(reader.GetOrdinal("FIRSTNAME")),
reader.GetString(reader.GetOrdinal("SUFFIX")),
reader.GetString(reader.GetOrdinal("MEMBERTYPESCODE"))
);
}
return null;
}
}
}
Get the MemberDetails;
var memberDetails = GetMemberDetail(1);
Populate the textbox;
TextBox.Text = memberDetails.Property;
Jawaid outside of the correct answers that were provided below I would also set SqlConnection con = null; and
SqlCommand cmd = null; outside the try and inside the try put the following
con = new SqlConnection(connectionString);
this way if there is an Error when doing cmd.Parameters.Add -- you can trap that exception
also dispose of the reader object
if (reader != null)
{
((IDisposable)reader).Dispose();
// somthing like that .. do the same for con and cmd objects or wrap them in a using() {}
}
cmd = new SqlCommand("usp_getmemberdetail", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#MEMBERSHIPGEN", SqlDbType.Int, 5));
cmd.Parameters["#MEMBERSHIPGEN"].Value = membershipgen;
ExecuteReader: Connection property has
not been initialized.
my coding is
protected void Button2_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection("Data Source=Si-6\\SQLSERVER2005;Initial Catalog=rags;Integrated Security=SSPI");
SqlDataReader rdr = null;
try
{
// 2. Open the connection
conn.Open();
// 3. Pass the connection to a command object
//SqlCommand cmd = new SqlCommand("select * from Customers", conn);
SqlCommand cmd=new SqlCommand ("insert into time(project,iteration)
values('"+this .name1 .SelectedValue +"','"+this .iteration .SelectedValue +"')");
//
// 4. Use the connection
//
// get query results
rdr = cmd.ExecuteReader();
// print the CustomerID of each record
while (rdr.Read())
{
Console.WriteLine(rdr[0]);
}
}
finally
{
// close the reader
if (rdr != null)
{
rdr.Close();
}
// 5. Close the connection
if (conn != null)
{
conn.Close();
}
}
}
}
}
use this and pass connection object :
SqlCommand cmd=new SqlCommand ("insert into time(project,iteration)values('"+this .name1 .SelectedValue +"','"+this .iteration .SelectedValue +"')",conn);
After SqlCommand cmd=new SqlCommand ("insert into time(project,iteration)values('....
Add
cmd.Connection = conn;
Hope this help
you have to assign connection to your command object, like..
SqlCommand cmd=new SqlCommand ("insert into time(project,iteration)values('"+this .name1 .SelectedValue +"','"+this .iteration .SelectedValue +"')");
cmd.Connection = conn;
All of the answers is true.This is another way. And I like this One
SqlCommand cmd = conn.CreateCommand()
you must notice that strings concat have a sql injection problem.
Use the Parameters
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters.aspx
You can also write this:
SqlCommand cmd=new SqlCommand ("insert into time(project,iteration) values (#project, #iteration)", conn);
cmd.Parameters.AddWithValue("#project",name1.SelectedValue);
cmd.Parameters.AddWithValue("#iteration",iteration.SelectedValue);
As mentioned you should assign the connection and you should preferably also use sql parameters instead, so your command assignment would read:
// 3. Pass the connection to a command object
SqlCommand cmd=new SqlCommand ("insert into time(project,iteration) values (#project, #iteration)", conn); // ", conn)" added
cmd.Parameters.Add("project", System.Data.SqlDbType.NVarChar).Value = this.name1.SelectedValue;
cmd.Parameters.Add("iteration", System.Data.SqlDbType.NVarChar).Value = this.name1.SelectedValue;
//
// 4. Use the connection
//
By using parameters you avoid SQL injection and other problematic typos (project names like "myproject's" is an example).
I like to place all my sql connections in using statements. I think they look cleaner, and they clean up after themselves when your done with them. I also recommend parameterizing every query, not only is it much safer but it is easier to maintain if you need to come back and make changes.
// create/open connection
using (SqlConnection conn = new SqlConnection("Data Source=Si-6\\SQLSERVER2005;Initial Catalog=rags;Integrated Security=SSPI")
{
try
{
conn.Open();
// initialize command
using (SqlCommand cmd = conn.CreateCommand())
{
// generate query with parameters
with cmd
{
.CommandType = CommandType.Text;
.CommandText = "insert into time(project,iteration) values(#name, #iteration)";
.Parameters.Add(new SqlParameter("#name", this.name1.SelectedValue));
.Parameters.Add(new SqlParameter("#iteration", this.iteration.SelectedValue));
.ExecuteNonQuery();
}
}
}
catch (Exception)
{
//throw;
}
finally
{
if (conn != null && conn.State == ConnectionState.Open)
{
conn.Close;
}
}
}