I have the following classes:
private static readonly string ConnectionString = "Dummy";
public static SqlConnection GetConnection()
{
SqlConnection Connection = new SqlConnection(ConnectionString);
return Connection;
}
public static SqlDataAdapter GetDataAdapter(string Query)
{
SqlDataAdapter Adapt = new SqlDataAdapter(Query, GetConnection());
return Adapt;
}
How do I dispose the SqlConnection object that is instantiated when GetConnection() is passed as parameter in my SqlDataAdapter constructor?
Will it get disposed automatically when I dispose my Adapt object in the method that called GetDataAdapter()?
If it's not possible to dispose it, how do you suggest to proceed?
Thanks for any help.
Description
If you dispose your SqlDataAdapter it does not dispose the SqlConnection too because its not clear if you want to use the connection again. You have to change your design to get this done.
I suggest to pass the SqlConnection to the GetDataAdapter function.
Sample
static void Main(string[] args)
{
using (SqlConnection connection = GetConnection())
{
using (SqlDataAdapter adapter = GetDataAdapter("YourQuery", connection))
{
}
// SqlDataAdapter is disposed
}
// SqlConnection is disposed
}
private static readonly string ConnectionString = "Dummy";
public static SqlConnection GetConnection()
{
SqlConnection Connection = new SqlConnection(ConnectionString);
return Connection;
}
public static SqlDataAdapter GetDataAdapter(string Query, SqlConnection connection)
{
SqlDataAdapter Adapt = new SqlDataAdapter(Query, connection);
return Adapt;
}
No, the adapter does not dipose the connection. You should change it to this at least:
public static SqlDataAdapter GetDataAdapter(SqlConnection connection, string Query)
{
SqlDataAdapter Adapt = new SqlDataAdapter(Query);
Adapt.Connection = connection;
return Adapt;
}
and use it like this
using (var connection = GetConnection())
using (var adapter = GetAdapter(connection, query))
{
// do stuff
}
This way you are also more flexible by being able to pass some other connection in - in case you need it for some exceptional circustances.
Related
Here is my database connection class.I want to access 'oracleCommand' object reference from another class.
public class DBConnection
{
//public OracleCommand oracleCommand;
public string cmd = "";
public void makeConnection()
{
//Opening connection
string connectionString = "XXXX";
OracleConnection con = new OracleConnection();
con.ConnectionString = connectionString;
con.Open();
OracleCommand oracleCommand = con.CreateCommand();
cmd = oracleCommand.CommandText;
//Clossing resources
con.Close();
oracleCommand.Dispose();
}
Then I want to execute the following query.
dbConnection.cmd = "SELECT COUNT(JOB_ID) FROM EmployeeTable WHERE STATUS='Pending'";
OracleDataReader Reader = dbConnection.oracleCommand.ExecuteReader();
Reader.Read();
But 'dbConnection.oracleCommand.ExecuteReader()' does not hit when debugging. Does anyone has an idea?
You´re hiding the member oracleCommand by a variable with the same name that exists within the makeConnection-method. Omit the declaration in your method:
public class DBConnection
{
public OracleCommand oracleCommand;
public string cmd = "";
public void makeConnection()
{
//Opening connection
string connectionString = "XXXX";
OracleConnection con = new OracleConnection();
con.ConnectionString = connectionString;
con.Open();
this.oracleCommand = con.CreateCommand(); // here
cmd = oracleCommand.CommandText;
//Clossing resources
con.Close();
oracleCommand.Dispose();
}
However that won´t help you much as you can´t do anything with the command, because yo dispose it once makeConnection has run.
Furthermore it´s a bad idea to even expose a command to the outside. You should instead expose the connection and create a new command for every statement to be executed on the db:
public class DBConnection
{
public OracleConnection { get; private set; }
public string cmd = "";
public void makeConnection()
{
//Opening connection
string connectionString = "XXXX";
this.Connection = new OracleConnection();
this.Connection.ConnectionString = connectionString;
con.Open();
}
Now create a second method that executes your query and returns its results:
public int CountPendingElements()
{
using(var cmd = this.Connection.CreateCommand())
{
cmd.CommandText = "SELECT COUNT(JOB_ID) FROM EmployeeTable WHERE STATUS='Pending'";
OracleDataReader Reader = cmd.ExecuteReader();
Reader.Read();
return reader.GetInt32(0);
}
}
The using-statement ensures that even in case of an exception within the code-block the command is disposed.
As an aside your class should implement IDisposable to dispose its underlying connection when you´re done with it.
I have a code like this in my program and I believe that it's not closing the connection after that the data is getting filled in.
public static string ConnectionInfo = System.Configuration.ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
public static DataTable ExecuteQuery(string query, string table)
{
SqlConnection cnn = new SqlConnection(ConnectionInfo);
SqlDataAdapter Adp = new SqlDataAdapter(query, cnn);
DataSet Ds = new DataSet();
Adp.Fill(Ds, table);
return Ds.Tables[table];
}
Is there any problem in this code ?
The only problem is that you are not using the using statement for the SqlConnection and the DataAdapter. However, DbDataAdapter.Fill opens and closes the connection implicitely.
public static DataTable ExecuteQuery(string query, string table)
{
using(SqlConnection cnn = new SqlConnection(ConnectionInfo))
using(SqlDataAdapter Adp = new SqlDataAdapter(query, cnn))
{
DataTable tbl = new DataTable();
Adp.Fill(tbl);
return tbl;
}
}
The connection object associated with the SELECT statement must be
valid, but it does not need to be open. If the connection is closed
before Fill is called, it is opened to retrieve data, then closed. If
the connection is open before Fill is called, it remains open.
Note that
the using statement will close the connection implicitely even on error
i have used DataAdapter.Fill(DataTable) because you're using a single table anyway
Edit: i've only just noticed that you are using a parameter for the table-name. You can also use DbDataAdapter.Fill(DataSet, String) instead. That does not change anything.
Add a using statement in order to close the connection reliably. This ensures that the connection is closed even if an exception occurs. Change your code as follows:
public static DataTable ExecuteQuery(string query, string table)
{
using(SqlConnection cnn = new SqlConnection(ConnectionInfo))
{
SqlDataAdapter Adp = new SqlDataAdapter(query, cnn);
DataSet Ds = new DataSet();
Adp.Fill(Ds, table);
return Ds.Tables[table];
}
}
Whatever the opening/closing of the connections should be done in try-catch-finally block.
And we should not be using "using"
[using (SqlConnection connection = new SqlConnection(connectionString))]
block. Because if something goes wrong with the network or any exception cause. Connection is not closed. So better to be use try-catch block.
public static DataTable ExecuteQuery(string query, string table)
{
DataSet Ds = new DataSet();
SqlConnection cnn = new SqlConnection(ConnectionInfo);
try{
SqlDataAdapter Adp = new SqlDataAdapter(query, cnn);
Adp.Fill(Ds, table);
return Ds.Tables[table];
}
catch{
throw;
}
finally{
cnn.Close();
}
}
As I'm not programming long time I would like to ask you if there is way to call result of this SqlCommand which is in class called klientClass
I was thinking that it could look something like this:
private static void ReadFirma()
{
string queryString =
"SELECT rocnik from FIRMA;";
using (SqlConnection connection = new SqlConnection(myConnection.DataSource.ConnectionString
))
{
SqlCommand command = new SqlCommand(
queryString, connection);
connection.Open();
int result= Convert.ToInt32(command.ExecuteScalar());
try
{
}
finally
{
reader.Close();
}
}
}
Because I need to insert this result into my report parameter here:
this.klientTableAdapter.Fill(this.prehled_zajezdu.HereReturnResult);
this.reportViewer1.RefreshReport();
I'm sorry for quiet low-quality question, hope not to receive down-votes.
This is how you can retrieve and use the value from the database in your Fill method (provided that the Fill method takes an argument of the type int and that the myConnection field is available from the static method)
private static int ReadFirma()
{
string queryString = "SELECT rocnik from FIRMA";
using (var connection =
new SqlConnection(myConnection.DataSource.ConnectionString))
using(var command = new SqlCommand(queryString, connection))
{
connection.Open();
return Convert.ToInt32(command.ExecuteScalar());
}
}
void SomeMethod()
{
this.klientTableAdapter.Fill(ReadFirma());
}
You can use DataTable object for your Goal.
private static DataTable ReadFirma()
{
string queryString = "SELECT rocnik from FIRMA";
using (var connection =
new SqlConnection(myConnection.DataSource.ConnectionString))
using(var command = new SqlCommand(queryString, connection))
{
connection.Open();
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = command;
da.Fill(dt);
return dt;
}
}
void SomeMethod()
{
this.klientTableAdapter.Fill(ReadFirma());
}
I have a problem with the following code. Please help.
What I am trying to do is pass a sqlcommand to a function which then returns a dataset.
The function 'Get data' takes sqlcommand as a parameter. This function is in class 'DatabaseUtilities'
//Initializing sql connection
static SqlConnection _Connection = new SqlConnection("Data Source=(local);Initial Catalog=db_Test;Integrated Security=True");
//Connection property
public static SqlConnection Connection
{
get {return _Connection;}
}
//The class that takes sqlcommand as parameter
public static DataSet GetData(SqlCommand Command)
{
_Connection.Open();
SqlDataAdapter Adapter = new SqlDataAdapter();
Adapter.SelectCommand = Command;
DataSet Table = new DataSet();
Adapter.Fill(Table);
_Connection.Close();
return Table;
}
This is how sqlcommand is passed into the above function. This function is from a different class.
public DataSet GetLogByDate(string SearchValue)
{
Command.CommandType = CommandType.StoredProcedure;
Command.Connection = DatabaseUtilities.Connection;
Command.CommandText = "sp_GetLogByDate";
Command.Parameters.AddWithValue("#LogDate", SearchValue);
return GetData(Command);
}
This code throws the fllowing error.
Invalid object name 'sp_GetLogByDate'.
I do have the above stored procedure in my database. I have no idea why this happened. Could anyone help?
You have to connect Command with Connection:
//The class that takes sqlcommand as parameter
public static DataSet GetData(SqlCommand Command)
{
Command.Connection = _Connection;
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!