For some database requests, I like to use raw ADO.NET.
In the context of a web request, I have created a class which provides an open IDbConnection
object.
I use a Dependency Injection library ("DI") to do this, scoping the object instantiated from this class to a web request. So, disposal of the object is handled by the DI container.
The abstraction for this class is simple and looks like this:
public interface IDbConnectionManager : IDisposable
{
IDbCommand BuildCommand(DbParameter[] parameters, string query);
IDbConnection GetOpenConnection();
}
And the concrete implementation, written for Sql Server, looks like this:
public class DbConnectionManager : IDbConnectionManager
{
public SqlConnection DbConnection;
public string ConnectionString { get; set; }
public DbConnectionManager(string connectionString)
{
ConnectionString = connectionString;
}
public IDbConnection GetOpenConnection()
{
return GetOpenSqlConnection();
}
private SqlConnection GetOpenSqlConnection()
{
if (ReferenceEquals(DbConnection, null))
{
DbConnection = new SqlConnection(ConnectionString);
}
if (DbConnection.State != ConnectionState.Open)
{
DbConnection.Open();
}
return DbConnection;
}
public IDbCommand BuildCommand(DbParameter[] parameters, string query)
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
if (string.IsNullOrWhiteSpace(query)) throw new ArgumentException(nameof(query));
var command = new SqlCommand { Connection = GetOpenSqlConnection() };
command.Parameters.AddRange(parameters);
command.CommandText = query;
return command;
}
public void Dispose()
{
DbConnection?.Dispose();
}
}
You can see the BuildCommand
method uses the GetOpenSqlConnection
for its connection.
The main reason I have taken this approach is because DbConnections
are expensive. But I'm not sure whether that relates to creating a connection or opening one.
I'm aware that connection pooling is available (if enabled), but I figured for simple web requests (think API), with perhaps just 2 queries to the database, that this would probably be a good approach.
And as can be seen, there's not a lot to the code.
I just wanted a bit of feedback on this code/approach. And if you can see any potential problems with it, by all means let me know that too.
As a last comment, I am aware that a developer could manually call Dispose
or use it in a using
block (thereby calling Dispose
).
This would be on me as lead developer to ensure that this doesn't happen and that devs understand that the DI container disposes of the object.