I am trying to get a better handle on decoupling my code, code reuse, etc.
I'm tired of typing the below every time I want to read some rows:
using(SqlConnection conn = new SqlConnection(myConnString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
/* do something with rows */
}
}
}
}
I understand there is LINQ to SQL (I don't like it), and the Entity Framework (still a baby). I have no problems having to type my queries out, I just don't want to have to type the command contruction, row iterator, etc each time.
I looked around and found something that I thought would work for me, and tried to implement it to make things easier for me. As you can see in the comment, I get an error that the SqlDataReader is closed. I'm guessing it's probably because of the using statement int the DataFactory.ExecuteReader() method. When the reader is returned, the dispose method is called on my SqlConnection and SqlCommand variables. Am I right there? If so, how should one manage the connection and command variables?
Edit: I updated my code example to better reflect what I am doing.
public class DataFactory
{
public DataFactory()
{}
public DataFactory(string connectionString)
{
_connectionString = connectionString;
}
protected _connectionString = "Data Source=Localhost, etc, etc";
private string ConnectionString
{
get{return _connectionString;}
}
public SqlConnection GetSqlConnection()
{
return new SqlConnection(ConnectionString);
}
public SqlDataReader ExecuteReader(string cmdTxt)
{
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
return cmd.ExecuteReader();
}
}
}
}
public IRepository<T>
{
T GetById(int id);
}
public MyTypeRepository: IRepository<MyType>
{
private static DataFactory _df = new DataFactory();
public MyType GetById(int id)
{
string cmdTxt = String.Format("SELECT Name FROM MyTable WHERE ID = {0}", id);
using(SqlDataReader rdr = _df.ExecuteReader(cmdTxt))
{
if(rdr.Read()) /* I get an error that the reader is already closed here */
{
return new MyType(
Convert.ToInt32(rdr["Id"]),
rdr["Name"]);
}
else
{
return null;
}
}
}
}
public class MyType
{
public MyType(int id, string name)
{
_id = id;
_name = name;
}
private string _name;
public string Name
{
get{return _name;}
}
private int _id;
public int Id
{
get{return _id;}
}
public override void ToString()
{
return string.Format("Name: {0}, Id: {1}", Name, Id);
}
}
public class Program
{
private static MyTypeRepository _mtRepo = new MyTypeRepository();
static void Main()
{
MyType myType = _mtRepo.GetById(1);
Console.WriteLine(myType.ToString());
}
}
I also would like to know if what I'm doing makes any sense, or, if not, how to achieve something similar so that I don't have to type the connection creation, etc so often.
Your method ExecuteReader will close the connection before returning the Reader. Instead it should be implemented something like:
public IDataReader ExecuteReader(string cmdTxt)
{
SqlConnection conn = new SqlConnection(...);
try
{
SqlCommand cmd = new SqlCommand(cmdTxt, conn);
conn.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch
{
conn.Close();
throw;
}
}
Callers of the ExecuteReader method will need to dispose the IDataReader:
using(IDataReader reader = ExecuteReader(commandText))
{
...
} // reader will be disposed here and will close the connection.
Note that the above does not call Dispose on the SqlCommand object. In my experience and from looking at SqlCommand with Reflector it's not necessary as long as the SqlConnection is disposed. But I believe the following will work if you do want to dispose it:
public IDataReader ExecuteReader(string cmdTxt)
{
SqlConnection conn = new SqlConnection(...);
SqlCommand cmd = null;
try
{
cmd = new SqlCommand(cmdTxt, conn);
conn.Open();
IDataReader reader =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
cmd.Dispose();
return reader;
}
catch
{
if (cmd != null) cmd.Dispose();
conn.Close();
throw;
}
}
It's very important that you close and/or dispose your data reader after using it then everyone who wants to use your DataFactory should remember to do that.I think it's a good idea to return a DataTable instead of SqlDataReader so that your DataFactory is not dependent to SqlDataReader.
I mean :
public DataTable ExecuteReader(string cmdTxt)
{
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader reader=cmd.ExecuteReader())
{
DataTable dt=new DataTable();
dt.Load(reader);
return dt;
}
}
}
}
EDIT:
Good point.I don't like data tables either ( We use NHibernate so I actually don't use data tables in our applications)
So if you'd like to map a data reader to your own objects maybe you can have a data mapper that maps data reader to your own objects I mean:
public T[] ExecuteReader<T>(string cmdTxt)
{
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
{
conn.Open();
using(SqlDataReader reader=cmd.ExecuteReader())
{
var result=new List<T>();
while(reader.Read())
result.Add(ObjectMapper.MapReader<T>(reader));
return result.ToArray();
}
}
}
}
What I do is I create an XML file with my queries and use an XSLT transformation to generate my DAL code CS files. You can go as fancy as you like, declare parameters in the XML and generate methods with appropriate signatures in the XSLT etc etc. I have a blog entry that covers, for a related topic, how to integrate the XSLT transformation into your Visual Studio project. Now one may argue that using a typed dataset is the same thing and is a free lunch, but in my case I use asynchronous DAL based on BeginExecute/EndExecute. None of the VS tools gets this approach right so I basically had to build my own.
I would say it's not really decoupling enough - basically any module you have with "using System.Data.SqlClient" is coupled to your database. The whole point of a DAL is that the application is coupled to the DAL and the DAL is coupled to the database.
Related
Although this question seems like have answers already but my case is different, here's how.
It works the first time but fails for subsequent requests.
I'm creating the connection in the main class and passing to the DB class as a dependency in it's constructor and it's meant to be re-used for each call.
public class DB
{
private SqlConnection conn;
public DB(SqlConnection conn)
{
this.conn = conn;
}
public List<Records> GetRecords()
{
using (conn){
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT * FROM Records", conn))
using (SqlDataReader reader = cmd.ExecuteReader())
{
List<Records> rows = new List<Records>();
while (reader.Read())
{
rows.Add(new Records(reader.GetString(1)));
}
return rows;
}
}
}
}
Caller class
string connection = $#"
Data Source=;
Initial Catalog=;
Persist Security Info=True;
User ID={env["DATABASE_USER"]};
Password={env["DATABASE_PASSWORD"]};";
Db db = new DB(new SqlConnection(connection));
db.GetRecords();
fail:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request. System.InvalidOperationException: The ConnectionString property has
not been initialized.
I'm not 100% sure, but I guess the problem is the
using(conn)
when the using is closed, the SqlConnection will be disposed.
so when you call again db.GetRecords();,
conn.Open() is not initialized. -> exception
You shouldn't use SQLConnection as a field, but as a local variable inside the method. Change your class to take in the connection string inside it's parameter instead of an instance of SqlConnection and initialize it in any method that use it:
public class DB
{
private string connectionString;
public DB(string connectionString)
{
this.connectionString = connectionString;
}
public List<Records> GetRecords()
{
using (var conn = new SqlConnection(connectionString)){
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT * FROM Records", conn))
using (SqlDataReader reader = cmd.ExecuteReader())
{
List<Records> rows = new List<Records>();
while (reader.Read())
{
rows.Add(new Records(reader.GetString(1)));
}
return rows;
}
}
}
}
For more details, read this.
I am Creating WinForm application using C# and SqlServer. I have to handle many database CRUD Queries on it. And also there are so many forms and so many controllers.
Now I want to know is, If i create common class for handle database connectivity with many methods for open connection, close connection, execute Sql command or do any other data retrievals. This method is good or bad?
or below method for run every query is good or bad?
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=MYDB"))
{
connection.Open();
// Pool A is created.
}
which method is better for performance and security?
Here are some points to think about when using a connection.
1) Dispose the connection object as soon as you no longer need it by using the using statement:
using (var conn = new SqlConnection(connectionstring))
{
// your sql magic goes here
}
2) If you're not disposing the object immediately, you can make sure the connection is closed using a try-finally statement:
var conn = new SqlConnection(connectionstring);
try
{
// do sql shizzle
}
finally
{
conn.Close();
}
3) To prevent SQL injection, use parameterized queries, never concatenated strings
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using(var comm = new SqlCommand("select * from FooBar where foo = #foo", conn))
{
comm.Parameters.Add(new SqlParameter("#foo", "bar"));
// also possible:
// comm.Parameters.AddWithValue("#foo", "bar");
using(var reader = comm.ExecuteReader())
{
// Do stuff with the reader;
}
}
}
4) If you're performing multiple update, insert or delete statements, and they all need to be succesful at once, use a transaction:
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using(var trans = conn.BeginTransaction())
{
try
{
using(var comm = new SqlCommand("delete from FooBar where fooId = #foo", conn, trans))
{
comm.Parameters.Add(new SqlParameter { ParameterName = "#foo", DbType = System.Data.DbType.Int32 });
for(int i = 0; i < 10 ; i++)
{
comm.Parameters["#foo"].Value = i;
comm.ExecuteNonQuery();
}
}
trans.Commit();
}
catch (Exception exe)
{
trans.Rollback();
// do some logging
}
}
}
5) Stored procedures are used similarly:
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using (var comm = new SqlCommand("FooBarProcedure", conn) { CommandType = CommandType.StoredProcedure })
{
comm.Parameters.Add(new SqlParameter("#FooBar", "shizzle"));
comm.ExecuteNonQuery();
}
}
(Source stored procedures: this Answer)
Multi threading: The safest way to use multi threading and SQL connections is to always close and dispose your connection object. It's the behavior the SqlConnection was designed for. (Source: Answer John Skeet)
Best practice is make a common DBHelper class and create CRUD methods into that class.
I am adding code snippet.This may help you.
web.config
<connectionStrings>
<add name="mssqltips"
connectionString="data source=localhost;initial catalog=mssqltips;Integrated Security=SSPI;"
providerName="System.Data.SqlClient" />
</connectionStrings>
DBHelper.cs
//Opening Connection
public SqlConnection GetConnection(string connectionName)
{
string cnstr = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
SqlConnection cn = new SqlConnection(cnstr);
cn.Open();
return cn;
}
//for select
public DataSet ExecuteQuery(
string connectionName,
string storedProcName,
Dictionary<string, sqlparameter=""> procParameters
)
{
DataSet ds = new DataSet();
using(SqlConnection cn = GetConnection(connectionName))
{
using(SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcName;
// assign parameters passed in to the command
foreach (var procParameter in procParameters)
{
cmd.Parameters.Add(procParameter.Value);
}
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
}
}
return ds;
}
//for insert,update,delete
public int ExecuteCommand(
string connectionName,
string storedProcName,
Dictionary<string, SqlParameter> procParameters
)
{
int rc;
using (SqlConnection cn = GetConnection(connectionName))
{
// create a SQL command to execute the stored procedure
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcName;
// assign parameters passed in to the command
foreach (var procParameter in procParameters)
{
cmd.Parameters.Add(procParameter.Value);
}
rc = cmd.ExecuteNonQuery();
}
}
return rc;
}
If you do not want to dispose context every time you can create repository class and inject SqlConnection inside.
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=MYDB"))
{
repository.SetConnection(connection);
var values = repository.GetSomething();
}
And Create Class:
public Class Repository
{
private SqlConnection _connection {get; set;}
public void SetConnection(SetConnection connection)
{
_connection = connection;
}
public string GetSomething()
{
_connection.Open();
//do stuff with _connection
_connection.Close();
}
}
Anyway I recommend you to read about ORM's (Entity Framework or Dapper) and SQL injection attack.
I have designed my application in a layered approach. I have a BusinessOP layer for each interface and a common data access layer. In my Data access layer I have Data Reader method like this.|
public SqlDataReader executeQuerys(string query01)
{
SqlConnection con = null;
SqlCommand com = null;
try
{
con = new SqlConnection(DBConnect.makeConnection());
con.Open();
com = new SqlCommand(query01, con);
return com.ExecuteReader(CommandBehavior.CloseConnection);
}
catch
{
com.Dispose();
con.Close();
throw;
}
This is the code for my DBConnection layer.
public static string makeConnection()
{
string con = ConfigurationManager.ConnectionStrings["MyDB.Properties.Settings.ConString"].ToString();
return con;
}
In my business layer I have methods like this each calling a specific stored procedure.
public SqlDataReader getLGDivID(string divName)
{
string query = "EXEC getLGDivID'" + divName + "'";
return new DataAccessLayer().executeQuerys(query);
}
As my business operation layer is unsecure, I want to have it with parameterized query in here I'm using string concatenation to pass parameters. Can anyone hint me how to modify it?
You can change your function a little bit:
public SqlDataReader executeQuerys(string query01, string paramName, string value)
{
SqlConnection con = null;
SqlCommand com = null;
try
{
con = new SqlConnection(DBConnect.makeConnection());
con.Open();
com = new SqlCommand(query01, con);
com.Parameters.AddWithValue(paramName, value);
com.Dispose();
con.Close();
}
catch
{
com.Dispose();
con.Close();
throw;
}
return com.ExecuteReader(CommandBehavior.CloseConnection);
}
then to use it:
public SqlDataReader getLGDivID(string divName)
{
string query = "EXEC getLGDivID #divName";
return new DataAccessLayer().executeQuerys(query, "#divName", divName);
}
EDIT:
As #silvermind pointed out, you should dispose your connection properly.
The way you have it now it will dispose connection only when you catch an exception.
This is bad, make use of IDisposable, for example:
public SqlDataReader executeQuerys(string query01, string paramName, string value)
{
using (SqlConnection con = new SqlConnection(DBConnect.makeConnection()))
{
try
{
con.Open();
com = new SqlCommand(query01, con);
com.Parameters.AddWithValue(paramName, value);
}
catch(SqlException ex)
{
//Handle the exceptio
//no need to dispose connection manually
//using statement will take care of that
}
}
return com.ExecuteReader(CommandBehavior.CloseConnection);
}
Can anyone please suggest me whether this code will cause concurrency or not.
This is a static class used in forms and and used for some database transactions.
This involves invoking of static function from asp.net pages and passing parameters as ref type.
I am using reference type.
As it is web based,does it Create some concurrency.
///
Here is code from my sample class.
public static class DataClass
{
static SqlConnection con = new SqlConnection(
ConfigurationManager.ConnectionStrings["sqlserverconnectionstring"]
.ConnectionString);
public static string GetCon()
{
return ConfigurationManager.ConnectionStrings["sqlserverconnectionstring"].ConnectionString;
}
public static void Conn(ref SqlConnection con)
{
if (con.State == ConnectionState.Closed)
{
con.Open();
}
}
public static DataSet GetDataSet(string qry)
{
SqlDataAdapter adp = new SqlDataAdapter(qry, con);
DataSet ds = new DataSet();
adp.Fill(ds);
return ds;
}
public static bool ExecuteCommand(ref SqlCommand cmd)
{
bool i =true;
cmd.Connection = con;
Conn(ref con);
SqlTransaction trans =con.BeginTransaction();
cmd.Transaction = trans;
try
{
cmd.ExecuteNonQuery();
trans.Commit();
}
catch
{
trans.Rollback();
i = false;
}
finally
{
cmd.Dispose();
con.Close();
}
return i;
}
}
Since you have defined a static SQLConnection, I believe it may cause concurrency issues.
static SqlConnection con = new SqlConnection (ConfigurationManager.ConnectionStrings["sqlserverconnectionstring"].ConnectionString);
If two different objects try to run a query, they will run them on the same instance of sql connection object.
Yes, that isn't thread-safe/ However, since SqlClient uses connection-pooling by default, you can just drop the static connection, and have each usage do something like:
using(var conn = OpenConnection()) {
...//code
}
where OpenConnection returns a new SqlConnection each time. This is not the same as a different underlying connection each time, and you will usually (in a winform) find a very low number of connections being used (1 if you get really lucky).
I'm new to asp.net so this might be really basic question, but i cant figure it out.
I found a bit of code on the internet, that connects to database. And i created a namespace and some classes to use the same code in different projects.
The code and my class is the following:
namespace databaseFunctions
{
public class databaseConnection
{
private static string databaseConnectionString()
{
return "DRIVER={MySQL ODBC 5.1 Driver}; ........";
}
public static DataTable getFromDatabase(string SQL)
{
DataTable rt = new DataTable();
DataSet ds = new DataSet();
OdbcDataAdapter da = new OdbcDataAdapter();
OdbcConnection con = new OdbcConnection(databaseConnectionString());
OdbcCommand cmd = new OdbcCommand(SQL, con);
da.SelectCommand = cmd;
da.Fill(ds);
try
{
rt = ds.Tables[0];
}
catch
{
rt = null;
}
return rt;
}
public static Boolean insertIntoDatabase(string SQL)
{
OdbcDataAdapter da = new OdbcDataAdapter();
OdbcConnection con = new OdbcConnection(databaseConnectionString());
OdbcCommand cmd = new OdbcCommand(SQL, con);
con.Open();
try
{
cmd.ExecuteNonQuery();
return true;
}
catch
{
return false;
}
}
}
There is no problem getting data from database, or insert data into some database.
But. when i try to get the last_insert_id() from the mysql database. i only get a zero.
This is why i think that this piece of code I've created and copied from internet, creates a new connection for every time i call the "getFromDatabase(SQL)"
Is there anyone that could help me with fixing this class getFromDatabase() to keep the databaseconnection alive until i tell the program to abandon the connection?
I guess it is the "new OdbcConnection" that should be changed? Is it possible to check if there already is a connection alive?
I've done this hundreds of times in classic asp, but now, with classes and stuff. I'm totally lost.
The problem you face is that you've coded yourself into a "new connection per action" corner. What you really want to aim for,and is considered best practice, is "new connection per batch of actions".
What I recommend in this case is to open connection when required, and close when disposed. What we'll do is move the odbc adapters to a larger scoped variable so that it can be accessed within the class.
namespace databaseFunctions
{
public class databaseConnection:IDisposable
{
private OdbcConnection con;
private string connectionString;
public databaseConnection(string connectionString){
this.connectionString = connectionString;
}
public void OpenConnection(){
if (con == null || con.IsClosed ){ // we make sure we're only opening connection once.
con = new OdbcConnection(this.connectionString);
}
}
public void CloseConnection(){
if (con != null && con.IsOpen){ // I'm making stuff up here
con.Close();
}
}
public DataTable getFromDatabase(string SQL)
{
OpenConnection();
DataTable rt = new DataTable();
DataSet ds = new DataSet();
OdbcCommand cmd = new OdbcCommand(SQL, con);
da.SelectCommand = cmd;
da.Fill(ds);
try
{
rt = ds.Tables[0];
}
catch
{
rt = null;
}
return rt;
}
public Boolean insertIntoDatabase(string SQL)
{
OpenConnection();
OdbcCommand cmd = new OdbcCommand(SQL, con);
con.Open();
try
{
cmd.ExecuteNonQuery();
return true;
}
catch
{
return false;
}
}
// Implementing IDisposable method
public void Dispose(){
CloseConenction();
}
}
}
Now the next time you use your class do something like
using (DatabaseConnection db = new DatabaseConnection()){
db.InsertIntoDatabase(...);
db.GetLastInsertID();
db.GetFromDatabase(...);
}
At the end of that code block, because it is IDisposeable, it will close that connection for you in the dispose method.
Things I changed:
implemented IDisposable interface
changed methods from static to class methods.
added new methods for opening closing connection
moved connection variable to class level scope
added an argument to the constructor that lets you pass in a connection string (you should put this connection string in you Web.Config
Edits:
constructor takes in connectionString per suggestion.
Yes, the code you posted is creating a new database connection every time a method is called, but that's not a problem. The problem is that it is not disposing the connection properly. The way to handle something like this is as follows:
using (OdbcConnection con = new OdbcConnection("yourconnectionsstring"))
{
con.open();
OdbcCommand command = new OdbcCommand("command_text",con);
command.ExecuteQuery(); //or what ever you need to do
}
That way the connection is being disposed properly since using is just syntactic sugar for try/finally
What you need to do is execute the 2 sql statements in the same transaction in a way that you insert the record in the first sql statement and retrieve the last inserted id on the next insert before ending the transaction. For example:
using (OdbcConnection con = new OdbcConnection("yourconnectionsstring"))
{
con.open();
OdbcTransaction tran = con.BeginTransaction()
OdbcCommand command = new OdbcCommand("first_sql_statement_here",con);
command.ExecuteNonQuery();
command.CommandText = "select last_insert_id();";
int result =command.ExecuteScalar();
tran.commit();
}
That is pretty much the idea.
You should let the connection pool handle your connections; That means you Close() every connection as soon as possible, and only create a new one at the last possible moment.
So yes - keep creating new ones for separate transactions.