This is interesting (to me anyway), and I'd like to see if anyone has a good answer and explanation for this behavior.
Say you have a singleton database object (or static database object), and you have it stored in a class Foo.
public class Foo
{
public static SqlConnection DBConn = new SqlConnection(ConfigurationManager.ConnectionStrings["BAR"].ConnectionString);
}
Then, lets say that you are cognizant of the usefulness of calling and disposing your connection (pretend for this example that its a one-time use for purposes of illustration). So you decide to use a 'using' block to take care of the Dispose() call.
using (SqlConnection conn = Foo.DBConn)
{
conn.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "SP_YOUR_PROC";
cmd.ExecuteNonQuery();
}
conn.Close();
}
This fails, throwing an exception on the call to open the connection, stating that the "ConnectionString property is not initialized". It's not an issue with pulling the connection string from the app.config/web.config. When you investigate in a debug session you see that Foo.DBConn is not null, but contains empty properties.
Why is this?
A little out of topic and not really answering your question but why using a singleton for SqlConnection when ADO.NET already uses a connection pool? Your code could have very well looked like this:
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["BAR"].ConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "SP_YOUR_PROC";
cmd.ExecuteNonQuery();
}
And one less thing to worry about in your program: connection lifecycle
Perhaps you do not have the corresponding connectionStrings node in you web/app.config?
<connectionStrings>
<add name="BAR"
connectionString="Data Source=localhost\sqlexpress;Initial Catalog=mydatabase;User Id=myuser;Password=mypassword;" />
The static field is evaluated sometime before it is used (not deterministically). See beforefieldinit for more detail. So the system may not be ready for creating an SQL-connection when it is called or maybe even properly create the static field after you use it.
Additionally, how would you handle a second SQL-command after you closed the first one? I don't know exactly how SqlConnection works, but after closing (note that this cals Dispose) and disposing the connection, your static Foo.DBConn should be gone, i.e. it won't be reevaluated.
If you want to keep your basic infrastructure, I would replace the static field with a static property which returns a new SqlConnection on get:
public static SqlConnection DBConn
{
get
{
return new SqlConnection(ConfigurationManager.ConnectionStrings["BAR"].ConnectionString);
}
}
Related
I am using npgsql to connect to a CockroachDb cluster, in code with each command I want to execute I create a new connection and open it! I wonder if creating a private field variable holding the connection and opening it then closing it is much better than my current approach?
static async Task Task1()
{
using (var conn = new NpgsqlConnection(connString))
{
conn.Open();
new NpgsqlCommand("SQL Query here", conn).ExecuteNonQuery();
conn.Close();
}
}
static async Task Task2()
{
using (var conn = new NpgsqlConnection(connString))
{
conn.Open();
new NpgsqlCommand("SQL Query here", conn).ExecuteNonQuery();
conn.Close();
}
}and so on ....
Not really: although possible, it's a bit of an anti pattern.
NpgsqlConnection inherits from DbConnection. And DbConnection is a general Microsoft abstract class that represents a database connection, which is IDisposable.
So when putting the conn in a using block, you implicitly call Dispose as soon as it goes out of scope. This will close the connection and clean up other stuff. You don't have to separately call Close.
What you could do, is make a general wrapper like
public static async Task NonQueryCommand(string command)
{
using (var conn = new NpgsqlConnection(connString))
{
conn.Open();
using (var cmd = new NpgsqlCommand(command, conn) // Also IDisposable
{
cmd.ExecuteNonQuery();
}
}
}
But you could lose all flexibility that way (the repository pattern can be bad if not used correctly).
Also check the official resources
I call a function which returns a SqlDataReader object to calling statement. I am confused where should I close the SqlDataReader object and SqlConnection object? In function or after calling it?
This is the function call:
SqlDataReader dr2= RetrieveSearcher();
pid = dr2[0].ToString();
This is the function:
protected SqlDataReader RetrieveSearcher()
{
String Q = "select price from tb3 where pid='12';
cn = new SqlConnection("data source=.\\sqlexpress; integrated security=true; initial catalog=singh");
cn.Open();
cmd = new SqlCommand(Q,cn);
dr1 = cmd.ExecuteReader();
dr1.Read();
return dr1;
}
Always use parameterized queries to avoid sql injection attacks and increase performance (most db servers can reuse execution plans with proper queries)
Never leave a connection open any longer than necessary!
Do not share db connections! Create it, use it, destroy it.
Wrap everything that implements IDisposable in a using block like Connections, Commands, DataReaders, etc. This ensures no resources remain open even in the event of an exception.
Use correct types in your db schema and read those types, do not blanket-convert everything to/from string! Example price seems like it should really be a decimal or numeric value and not a string so do not store it as a string and do not read it back as a string.
Retrieve the connection strings by name from the app.config or web.config (depending on the application type), do not hard code the strings into your connections or anywhere else.
About your logic
Change your method to return a custom type like a piece of data. This ensures proper SoS (Separation of Concerns). Do not return a DataReader! This will abstract the whole database call from the caller which is what you should strive for.
protected SomeType RetrieveSearcherData(string pid)
{
const string Q = "SELECT price FROM tb3 WHERE pid = #pid";
using(var cn=new SqlConnection())
using(var cmd=new SqlCommand(Q,cn))
{
// I do not know what pid is but use tho correct type here as well and specify that type using SqlDbType
cmd.Parameters.Add(new SqlParameter("#pid", SqlDbType.VarChar, 100) { Value = pid});
cn.Open();
using(var dr1= cmd.ExecuteReader())
{
if(dr1.Read())
{
var result = dr1.GetDecimal(0);
// read something and return it either in raw format or in some object (use a custom type)
}
else
return null; // return something else that indicates nothing was found
}
}
}
Do you really want to open a connection each time you call into this function? Having one thread deal with multiple connections is a sure fire way to get deadlocks.
If you still want to do #1, I'd recommend having your RetrieveSearcher return the data it needs in a List<T> or heck, just return a DataTable and deal with that. That way the function can close the connection that it opened.
If you still REALLY want to return a SqlDataReader then you need to make sure that you can close the connection that you opened. SqlDataReader doesn't expose a SqlConnection directly, so you can't directly close the connection after you leave the RetrieveSearcher method. However, you can do this:
dr1 = cmd.ExecuteReader(CommandBehavior.CloseConnection);
That will close the connection when the reader is closed. So, then you can do:
using (SqlDataReader dr2 = RetrieveSearcher()) {
pid=dr2[0].ToString();
}
I'm assuming of course that you REALLY need more than just one string. :) If you REALLY only need one string you just be returning the string and calling cmd.ExecuteScalar();
I have the following code in DAL layer:
using(OracleConnection conn= new OracleConnection(connString))
using(OracleCommand cmd = new OracleCommand(sql.ToString(), conn))
{
conn.Open();
}
The above object creation is done at multiple places of DAL methods. I am looking if there is any way to optimize this object creation, instead of repeating it several times in my code.
Any suggestions/advise would be helpful.
Thanks,
WH
There's really not a good way to do this without requiring almost the same amount of code each time to make sure you set it up properly because it needs to be disposable. Anything outside of this: using(OracleCommand cmd = new OracleCommand(sql.ToString(), conn)) will despose the connection. Is there a reason why you can't move to using an ORM like Entity Framework? That aside you can create a class that will return a OracleConnection that you would then call .Open() on but you would need to inherit IDisposable and call .Dispose() on it when you are done or you will fill up your app pool. You could do something like this in a data manager class:
public void RunQuery(string query)
{
using(OracleConnection conn= new OracleConnection(connString))
using(OracleCommand cmd = new OracleCommand(query, conn))
{
conn.Open();
//do your data transaction here
}
}
That would let you pass queries to a single place to be handled. Still not a great solution but will let you keep it in one place. To use it:
new YourDataClass().RunQuery("INSERT...");
You would need a few different classes to handle things like selects, etc to return data if needed.
Edit: This is just conceptual. You would have a single data class and just send queries to it. Then you aren't reproducing the same connection code everywhere. You'll need to add more to this to have it cover all aspects of interfacing with your database but this is the general concept. This is written in one class and used over and over in your application. Again, an ORM would be far better but this will accomplish what you're trying to do.
public class YourDataClass
{
public void RunQuery(string query) //for add, update where you don't want to return anything, could add a second parameter to send in a List<SqlParameter> to add data.
{
using(OracleConnection conn= new OracleConnection(connString))
using(OracleCommand cmd = new OracleCommand(query, conn))
{
conn.Open();
//do your data transaction here
cmd.ExecuteNonQuery();
}
}
public DataTable GetData(string query) //for selecting data
{
using(OracleConnection conn= new OracleConnection(connString))
using(OracleCommand cmd = new OracleCommand(query, conn))
{
conn.Open();
//do your data transaction here
dt.Add(cmd); //add data to data table or dataset
return dt;
}
}
}
Such as so: Creating it in a method and assigning it to a field. Passing that field to a method and then assigning it to a variable of a using-statement (Which is the only Dispose being called).
SqlCommand CreateSqlCommand()
{
SqlCommand cmd1 = new SqlCommand();
return cmd1;
}
void UseSqlCommand(SqlCommand cmd4)
{
using (SqlCommand cmd3 = cmd4)//Is this using-statement enough?
{
//use cmd3 here...
}
}
And used:
SqlCommand cmd2 = CreateSqlCommand();
UseSqlCommand(cmd2);
Extra detail: Will the GC collect all of these variables on its next round or not? Why not - see David M. Kean's answer here.
EDIT
I've added
cmd2.CommandText = "";
after the previous (last) line. And there's no error thrown.
Why? It should be disposed already! Never mind. A disposed object can be referenced...
Please do not concentrate on the example, rather do - on the question itself. Thanks.
Yes, the using statement will call Dispose() after the block has completed on the referenced variable. This is a good and bad thing, suppose that you create a sql command and store the result in a variable cmd, then you pass that variable to another method that uses and disposes cmd. Now you are stuck with a variable that is disposed, and if you try to use it, it might throw an ObjectDisposedException.
SqlCommand cmd = CreateSqlCommand();
UseSqlCommand(cmd);
//Uh oh, cmd can still be used, what if I tried to call UseSqlCommand(cmd) again?
It would be more clear and secure to dispose of that object outside of the method(Like Jordão posted).
using(SqlCommand cmd = CreateSqlCommand())
{
UseSqlCommand(cmd);
}
Now you completely control the object and limit it's scope.
Control the scope of using from outside:
using (SqlCommand cmd2 = CreateSqlCommand()) {
UseSqlCommand(cmd2);
}
...
void UseSqlCommand(SqlCommand cmd4) {
// use cmd4 here...
}
And maybe rename UseSqlCommand to something different, like ExecuteSqlCommand.
The purpose of the using statement is not to dispose of variables, but rather object instances. Variables are often used for the purpose of identifying object instances, but reference-type variables don't hold object--they hold "object identifiers".
If one says e.g. var myPort = new System.Io.Ports.SerialPort("COM1", ...); myPort.Open(), the SerialPort object will ask the system to let it use the COM1 serial port and not let anyone else use it until further notice. The system will generate a handle for that port, and set some flags so that only code which has that handle will be allowed to use the port. Once the object is created (say the system arbitrarily assigns it an ID of #8675309), the system will store that ID into the variable myPort).
When code no longer needs to use that serial port, it is important that someone tell object #8675309 that it is no longer needed, so it can in turn tell the system that it should make COM1 available to other applications. This would typically be done by calling Dispose on a variable which holds a reference to object #8675309. Once that is done, every variable that holds a reference to object #8675309 will hold a reference to an object whose Dispose method has been called. Note that the Dispose method won't actually affect any of those variables (unless they are rewritten within the code of the method itself). Any variables which held "object #8675309" before the call will continue to do so after. The object will have released its serial port, so the reference which is stored those variables will no longer be useful for much, and the code that uses those variables may want them to be cleared, but the SerialPort object won't care one way or the other.
I think this is what you're trying to do:
public class MySqlClass : IDisposable
{
private SqlConnection conn { get; set; }
public MySqlClass(string connectionstring)
{
conn = new SqlConnection(connectionstring);
}
public void DoSomething1(string tsql)
{
using (SqlCommand comm = new SqlCommand(tsql, conn)) {
conn.Open();
}
}
public void DoSomething2(string tsql)
{
using (SqlCommand comm = new SqlCommand(tsql, conn)) {
conn.Open();
}
}
//DISPOSE STUFF HERE
}
Use...
using (MySqlClass MySQL = new MySqlClass())
{
MySQL.DoSomething1();
MySQL.DoSomething2();
}
* UPDATE *
Updated >>>> EXAMPLE <<<<< Point is you create single instance of SqlConnection above, and you can resuse it. The class implements IDisposable so you can use the using() method to auto dispose. Better than passing instances of SqlCommand like you mentioned.
Which pattern is better for SqlConnection object? Which is better in performance?
Do you offer any other pattern?
class DataAccess1 : IDisposable
{
private SqlConnection connection;
public DataAccess1(string connectionString)
{
connection = new SqlConnection(connectionString);
}
public void Execute(string query)
{
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = query;
command.CommandType = CommandType.Text;
// ...
command.Connection.Open();
command.ExecuteNonQuery();
command.Connection.Close();
}
}
public void Dispose()
{
connection.Dispose();
}
}
VS
class DataAccess2 : IDisposable
{
private string connectionString;
public DataAccess2(string connectionString)
{
this.connectionString = connectionString;
}
public void Execute(string query)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = query;
command.CommandType = CommandType.Text;
// ...
command.Connection.Open();
command.ExecuteNonQuery();
command.Connection.Close();
}
}
public void Dispose()
{
}
}
There's no real way to answer this question. The short, canonical answer is that the connection should stay alive for the lifetime of your unit of work. Because we have no way of knowing how DataAccess is used (does it exist for the lifetime of your application, or do you instantiate it and dispose it whenever you do something?), it's impossible to give a concrete answer.
That being said, I would recommend the first pattern, but instantiate and dispose of your DataAccess object as needed; don't keep it around longer than necessary.
Suggest going with DataAccess2. It's a personal preference though. Some might even suggest your class be static. It'd be difficult to say that one is more performant than the other. You're on the path of IDisposable, which is great.
I'd be happy to read and maintain both styles shown above in your question.
Consider having your DAL be able to read the connection string from a .config as well, rather than exclusively allowing the value to be passed in the constructor.
public DataAccess2(string connStr)
{
this.connectionString = connStr;
}
public DataAccess2()
{
this.connectionString =
ConfigurationManager.ConnectionStrings["foo"].ConnectionString;
}
Consider wrapping your SqlCommand in a using as well.
using (var conn = new SqlConnection(connectionString))
{
using(var cmd = conn.CreateCommand())
{
}
}
I think it depends on how your DataAccess object is intended to be used, if it's used within a 'using' clause then the connection is guaranteed to be disposed of after it's done.
But in general I prefer the second pattern as the sql connection is created and disposed of within the Execute method so it's less likely to be left open when you forget to dispose of your DataAccess object.
Considering that sql connection can be a scarse resource I think every attempt should be made to ensure that they're not wasted.
The first will result in errors if you make concurrent calls.
The second will ensure you use a clean connection for each command resulting in more connections being made.
I agree with the statements above that it depends on the scenario for use, to get over the problem related to the first I have a wrapper that needs to use such a pattern so I set a field value boolean to show that a command is being executed on the connection already then "queue" the next command for execution.
There will of course be situations where you may prefer to use multiple connections ...