Polymorphic class using lambda - c#

I'm not sure if this is possible. I'm trying to learn a little bit about lambda expressions because of a program that I am writing with my buddy. So he has a Database class that talks with a MS SQL server. I wanted to do some testing on the classes and so made a simple Compact Database that in my TextFixtureSetup I populate the tables (2 tables right now) and then in teardown I delete all the data. his database class uses something like this for his SQL connection
protected void WithConnection(Action<SqlConnection> sqlBlock)
{
try
{
using (SqlConnection connection = new SqlConnection(this.ConnectionString))
{
connection.Open();
sqlBlock(connection);
}
}
catch (Exception ex)
{
Console.WriteLine(#"Exception during database connection: {0}", ex);
}
}
I think I found a post that Jon Skeet answered using almost the same code. https://stackoverflow.com/a/1063112/1329396
I think that this is cool, but my mock database uses SQLCEReader. I did a little research and found that they share a common class System.Data.Common.DbDataReader and it is only one level up. I haven't checked much with it, but i was thinking about if it was possible to use a polymorphic style way to use the WithConnection style of programming that would allow me to use my SQLCeDataReader and his SQLDataReader. Is there a way to do this

Use a factory function. If you can get by with just using a DbConnection for all your Actions you don't need generics:
protected void WithConnection(Action<DbConnection> sqlBlock, Func<DbConnection> dbCxnFactory)
{
try
{
using (DbConnection connection = dbCxnFactory())
{
connection.ConnectionString = this.ConnectionString;
connection.Open();
sqlBlock(connection);
}
}
catch (Exception ex)
{
Console.WriteLine(#"Exception during database connection: {0}", ex);
}
}
If you want to specialize, some actions to SqlConnection only and some to SqlCeConnection only, then you can make it generic:
protected void WithConnection<T>(Action<T> sqlBlock, Func<T> dbCxnFactory) where T : DbConnection
{
try
{
using (T connection = dbCxnFactory())
{
connection.ConnectionString = this.ConnectionString;
connection.Open();
sqlBlock(connection);
}
}
catch (Exception ex)
{
Console.WriteLine(#"Exception during database connection: {0}", ex);
}
}
If you don't want to pass in the factory as a parameter, you can use a generic with new()
protected void WithConnection<TCxn>(Action<TCxn> sqlBlock) where TCxn : DbConnection, new()
{
try
{
using (var cxn = new TCxn())
{
cxn.ConnectionString = this.ConnectionString;
cxn.Open();
sqlBlock(cxn);
}
}
catch (Exception ex)
{
Console.WriteLine(#"Exception during database connection: {0}", ex);
}
}

Related

MVC SQL connection initialization

I am working on a MVC web page that edits a SQL DB table. In my controller, I have a DB call to increment an entity table. Then if successful, creates a new row in my target table (not the entity table).
The problem I am running into is I keep getting the following error:
The ConnectionString property has not been initialized.
However this only happens after the entity table has been incremented. Not sure where to go on this, so I am hoping that by posting some code, someone would be able to help me find my error.
so here is the obligatory code:
My SQL Connection:
private SqlConnection con;
public BaseRepository()
{
con = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlServerConnection"].ToString());
}
My Entity Table Increment Call:
public int GetNextId()
{
try
{
using (con)
{
DynamicParameters dynParam= new DynamicParameters();
dynParam.Add("#entity_name", "insert_object ");
con.Open();
var value = con.Execute(SP_GET_NEW_ID, dynParam, commandType: CommandType.StoredProcedure);
con.Close();
return value;
}
}
catch (Exception ex) { throw ex; }
}
Finally, here is the Row Insert Code:
public int InsertRowCode(InsertObject ccModel, UserModel appUser)
{
var value = GetNextId();
if (value == 1)
{
try
{
using (con)
//this is where the code breaks and jumps the the exception ex in my catch
{
con.Open();
var dP = new DynamicParameters();
//(add 14 dynamic Parameters here)
var result = con.Execute(SP_SAVE_CORRECTION_CODES, dP, commandType: CommandType.StoredProcedure);
con.Close();
return result;
}
}
catch (Exception ex)
{
throw ex;
}
}
else { throw new Exception("Busted"); }
}
Any help is greatly appreciated. TIA
Don't use shared connection objects.
When you exit this block:
using (con)
{
//...
}
That connection object is now disposed and can't be used anymore. Don't worry about trying to optimize your connections, the connection pool does a very good job of that already. Create your connection objects where you need them, use them, and dispose them in a tight scope:
using (var con = new SqlConnection(connectionString))
{
//...
}
As a side note, this is superfluous:
catch (Exception ex)
{
throw ex;
}
That catch block isn't doing anything for you, and is actually deleting important information about the exception. Just remove that try/catch entirely.
If, on the other hand, you ever do want to do something with an exception before re-throwing it, just use the keyword throw by itself:
catch (Exception ex)
{
// log something, etc.
throw;
}
This would allow the exception to continue up the stack unmodified, preserving the actual error information.

Right way to test connection strings

I tried this code on an array of 3 connection strings without any complaints.My question is, is it okay to invoke multiple dispose calls on the same object?
foreach (var s in strings)
{
connection.ConnectionString = s;
connection.Open();
connection.Close();
connection.Dispose();
}
Here is one way to do it:
bool TestConnection<T>(string connectionString) where T : IDbConnection, new
{
using(T con = new T())
{
con.ConnectionString = connectionString;
connection.Open();
return true;
}
}
Another way to implement connection testing code is with an extension method (note this does not dispose the connection object):
public static Tuple<bool, Exception> TestConnection(this IDbConnection connection)
{
try
{
connection.Open();
connection.Close();
return new Tuple<bool, Exception>(true, null);
}
catch(Exception e)
{
return new Tuple<bool, Exception>(false, e);
}
}
Please note in this version I'm returning a Tuple of bool and Exception so whoever use this code can get the information on why the connection failed, but not have to wrap the call in a try...catch block. Of course, you can choose to simply return a bool just like in the first example, this is just for demonstration purposes.
You should fix your code this way:
foreach (var s in strings)
{
connection.ConnectionString = s;
connection.Open();
connection.Close();
}
Connection doesn't need to dispose, or atleast you shoudln't dispose an object that you want to use again.
Anyway this isn't a good approach.
You should have a
using(DbContext db = new DbContext()){
//SQL Actions
}
for every db relative code, to avoid problems ^^
public bool TestConnection(IDbConnection con)
{
using (con)
{
try
{
con.Open();
con.Close();
return true;
}
catch
{
return false;
}
}
}
It's "ok" with what you are doing (completely different connect everytime with no ran queries) but as Amy said in the comments, it really doesn't get you anything special. Should probably abide by the wisdom of not reusing disposed objects.
Also for SqlConnection, calling Close then dispose is repetitive since it will call its close upon dispose.
Going to throw my code into the mix as well, comments in code:
private bool DBValidCheck(string connection)
{
//Using statement releases the object that implement iDisposable once it exits the block. Takes care of the dispose
using (var connection = new SqlConnection(connection))
{
try
{
connection.Open();
return true;
}
catch
{
return false;
}
}
}

How to insert data quickly into SQL Server using a stored procedure

I have an application in C# which receives data from different clients and insert that data into SQL Server. I get the data every second, or even faster, but I am facing some problem with my code:
static SqlConnection objSqlConn = null;
static SqlCommand objSqlCmd = null;
public static void SaveClientHistory(String strMessage, String strClientIP)
{
try
{
using (objSqlConn = new SqlConnection(strConnectionString))
{
using (objSqlCmd = new SqlCommand("procInsertHistory", objSqlConn))
{
objSqlCmd.CommandTimeout = 0;
objSqlCmd.CommandType = CommandType.StoredProcedure;
objSqlCmd.Parameters.AddWithValue("#strMessage", strMessage);
objSqlCmd.Parameters.AddWithValue("#strClientIP", strClientIP);
objSqlConn.Open();
objSqlCmd.ExecuteNonQuery();
}
}
}
catch (Exception Ex)
{
throw Ex;
}
finally
{
if(objSqlConn != null && objSqlConn.State != ConnectionState.Closed)
{
objSqlConn.Close();
objSqlConn.Dispose();
}
}
}
Different types of exceptions occurred:
The connection was not closed. The connection's current state is connecting.
Internal connection fatal error.
ExecuteNonQuery requires an open and available Connection. The connection's current state is connecting.
Please, advise me if there is any error in above code or suggest any other way to accomplish this task.
Thanks
Edited - simplified the procedure further to better troubleshoot the issue: removed the try/catch because it wasn't doing anything helpful; method is no longer static; all inputs are now passed in as parameters - including strConnectionString; the connection timeout is explicitly set; the connection is opened before the SqlCommand object is instantiated; the command timeout is now 10 seconds.
As performance is a concern of yours, note that you should not be worried about trying to keep a connection open for re-use. By default, SQL Server connection pooling is turned on, so there is no need to attempt to cache connections with your own methodology.
There seems like there is something going on besides attempting to open a connection and executing a non-query, so I tried to simplify your code a little further. I hope it helps with troubleshooting your issue.
public int SaveClientHistory(String strConnectionString, String strMessage, String strClientIP)
{
// You can double-up using statements like this (for slightly better readability)
using (SqlConnection objSqlConn = new SqlConnection(strConnectionString))
{
objSqlConn.ConnectionTimeout = 10; // Creating a connection times out after ten seconds
objSqlConn.Open();
using (SqlCommand objSqlCmd = new SqlCommand("procInsertHistory", objSqlConn))
{
objSqlCmd.CommandTimeout = 10; // Creating a command times out after ten seconds
objSqlCmd.CommandType = CommandType.StoredProcedure;
objSqlCmd.Parameters.AddWithValue("#strMessage", strMessage);
objSqlCmd.Parameters.AddWithValue("#strClientIP", strClientIP);
return objSqlCmd.ExecuteNonQuery();
}
}
}
It seems that all three errors are related with connection. In one of my applications, I implement you function like bellow. I hope this help you:
public static void SaveClientHistory(String strMessage, String strClientIP)
{
SqlConnection objSqlConn = new SqlConnection(strConnectionString);
SqlCommand objSqlCmd = new SqlCommand("procInsertHistory", objSqlConn)
objSqlCmd.CommandType = CommandType.StoredProcedure;
objSqlCmd.Parameters.AddWithValue("#strMessage", strMessage);
objSqlCmd.Parameters.AddWithValue("#strClientIP", strClientIP);
try{
objSqlConn.Open();
objSqlCmd.ExecuteNonQuery();
}
catch (Exception Ex)
{
throw Ex;
}
finally
{
if(objSqlConn.State == ConnectionState.Open)
objSqlConn.Close();
}
}

Proper way of using BeginTransaction with Dapper.IDbConnection

Which is the proper way of using BeginTransaction() with IDbConnection in Dapper ?
I have created a method in which i have to use BeginTransaction(). Here is the code.
using (IDbConnection cn = DBConnection)
{
var oTransaction = cn.BeginTransaction();
try
{
// SAVE BASIC CONSULT DETAIL
var oPara = new DynamicParameters();
oPara.Add("#PatientID", iPatientID, dbType: DbType.Int32);
..........blah......blah............
}
catch (Exception ex)
{
oTransaction.Rollback();
return new SaveResponse { Success = false, ResponseString = ex.Message };
}
}
When i executed above method - i got an exception -
Invalid operation. The connection is closed.
This is because you can't begin a transaction before the connection is opened. So when i add this line: cn.Open();, the error gets resolved. But i have read somewhere that manually opening the connection is bad practice!! Dapper opens a connection only when it needs to.
In Entity framework you can handle a transaction using a TransactionScope.
So my question is what is a good practice to handle transaction without adding the line cn.Open()... in Dapper ? I guess there should be some proper way for this.
Manually opening a connection is not "bad practice"; dapper works with open or closed connections as a convenience, nothing more. A common gotcha is people having connections that are left open, unused, for too long without ever releasing them to the pool - however, this isn't a problem in most cases, and you can certainly do:
using(var cn = CreateConnection()) {
cn.Open();
using(var tran = cn.BeginTransaction()) {
try {
// multiple operations involving cn and tran here
tran.Commit();
} catch {
tran.Rollback();
throw;
}
}
}
Note that dapper has an optional parameter to pass in the transaction, for example:
cn.Execute(sql, args, transaction: tran);
I am actually tempted to make extension methods on IDbTransaction that work similarly, since a transaction always exposes .Connection; this would allow:
tran.Execute(sql, args);
But this does not exist today.
TransactionScope is another option, but has different semantics: this could involve the LTM or DTC, depending on ... well, luck, mainly. It is also tempting to create a wrapper around IDbTransaction that doesn't need the try/catch - more like how TransactionScope works; something like (this also does not exist):
using(var cn = CreateConnection())
using(var tran = cn.SimpleTransaction())
{
tran.Execute(...);
tran.Execute(...);
tran.Complete();
}
You should not call
cn.Close();
because the using block will try to close too.
For the transaction part, yes you can use TransactionScope as well, since it is not an Entity Framework related technique.
Have a look at this SO answer: https://stackoverflow.com/a/6874617/566608
It explain how to enlist your connection in the transaction scope.
The important aspect is: connection are automatically enlisted in the transaction IIF you open the connection inside the scope.
Take a look at Tim Schreiber solution which is simple yet powerful and implemented using repository pattern and has Dapper Transactions in mind.
The Commit() in the code below shows it.
public class UnitOfWork : IUnitOfWork
{
private IDbConnection _connection;
private IDbTransaction _transaction;
private IBreedRepository _breedRepository;
private ICatRepository _catRepository;
private bool _disposed;
public UnitOfWork(string connectionString)
{
_connection = new SqlConnection(connectionString);
_connection.Open();
_transaction = _connection.BeginTransaction();
}
public IBreedRepository BreedRepository
{
get { return _breedRepository ?? (_breedRepository = new BreedRepository(_transaction)); }
}
public ICatRepository CatRepository
{
get { return _catRepository ?? (_catRepository = new CatRepository(_transaction)); }
}
public void Commit()
{
try
{
_transaction.Commit();
}
catch
{
_transaction.Rollback();
throw;
}
finally
{
_transaction.Dispose();
_transaction = _connection.BeginTransaction();
resetRepositories();
}
}
private void resetRepositories()
{
_breedRepository = null;
_catRepository = null;
}
public void Dispose()
{
dispose(true);
GC.SuppressFinalize(this);
}
private void dispose(bool disposing)
{
if (!_disposed)
{
if(disposing)
{
if (_transaction != null)
{
_transaction.Dispose();
_transaction = null;
}
if(_connection != null)
{
_connection.Dispose();
_connection = null;
}
}
_disposed = true;
}
}
~UnitOfWork()
{
dispose(false);
}
}
There are two intended ways to use transactions with Dapper.
Pass your IDbTranasction to your normal Dapper call.
Before:
var affectedRows = connection.Execute(sql, new {CustomerName = "Mark"});
After:
var affectedRows = connection.Execute(sql, new {CustomerName = "Mark"}, transaction=tx);
Use the new .Execute extension method that Dapper adds to IDbTransaction itself:
tx.Execute(sql, new {CustomerName = "Mark"});
Note: the variable tx comes from IDbTransaction tx = connection.BeginTransaction();
This is how you're supposed to use transactions with Dapper; neither of them are TranasctionScope.
Bonus Reading
https://stackoverflow.com/a/67474832/12597

Correct SqlConnection declaration

The problem is that I have used my SqlConnection as a public static connection, thinking this might be the problem causing form time to time an error :
*the connection is not open or the connection was already open
So is it ok to use one statement of SqlConnection in a static class?
So that I could Declare it only once, I know I could use connectionString in web.config
ConfigurationManager.ConnectionStrings["conn"].ConnectionString ...
but I like it to stay unrelated to web.config settings or servers name.
ReEdit :
as it is realy two methods within same class theres also another class in that main class
but this is not what's important rather than using same connection for all
executions ! so you say that even though i re edited with right code of my helprer class
this is wrong ?
public static class myDBhelper
{
public static SqlConnection Conn = new SqlConnection ("server=(local);Initial Catalog=dbName;Integrated Security=True");
public static int ExecSQLint(string TblintSQL)
{
int anIntValue=0;
SqlCommand TblintCMD = new SqlCommand(TblintSQL, Conn);
try
{
Conn.Open();
anIntValue = Convert.ToInt32(TblintCMD.ExecuteScalar());
}
catch (System.Data.SqlClient.SqlException ex)
{
throw new Exception("No Can Do: " + ex.Message);
}
finally
{
Conn.Close();
}
return anIntValue;
}
public static string ExecSQLstring(string TblStrSQL)
{
string strValue="";
SqlCommand TblStrCMD = new SqlCommand(TblStrSQL, Conn);
try
{
Conn.Open();
strValue = TblStrCMD.ExecuteScalar().ToString();
}
catch (System.Data.SqlClient.SqlException ex)
{
throw new Exception("No Can Do: " + ex.Message);
}
finally
{
Conn.Close();
}
return strValue;
}
}
The main issue I suspect is those two options :
SqlConnection Conn = new SqlConnection("Data Source=(local);Integrated Security=True;database=dbName")
in my DBhelper class I was using this declaration
SqlConnection Conn = new SqlConnection("server=(local);Initial Catalog=dbName;Integrated Security=True");
could that be unstable or error prone ?
p.s.: I am executing commands via try catch
try
{
Conn.Open();
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
throw new Exception("No Can Do: " + ex.Message);
}
finally
{
Conn.Close();
}
Is Using statement more appropriate? Although it is not my problem I was thinking... if I am already trying to do it 'by the book'...
Is any method here actually wrong among those ?
Keeping Connection as static is not a common way to use connection to database. It could lead to exception as you mentioned when application is working on web or multi-thread environment.
Image that thread 1 executing command 1 is the same connection with thread 2 executing command 2. Your ex: TblintCMD and TblStrCMD. When thread 1 finishs, it closed connection, meanwhile thread 2 is still executing command on close connection
Your two options are not the problem.
The best way is to use using keyword and create connection when needed:
using (var connection = new SqlConnection("yourConnectionString"))
{
connection.Open();
...
}
using is similar with:
var connection = new SqlConnection("connectionString");
try
{
connection.Open();
....
}
finally
{
connection.Close();
}
So, you don't need to know when to close Connection.
Behind the scene, ADO.NET uses connection pool to manage connections for you automatically, so you should not care much how many connections open.
using(var conn=new. SqlConnection( "server=(local);Initial Catalog=dbName;Integrated Security=True"))
{
conn.Open();
}
public SqlConnection GetSqlConnection()
{
SqlConnection sql = new SqlConnection();
sql.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["SchoolContext"].ToString();
return sql;
}

Categories

Resources