I've been playing with Dapper, but I'm not sure of the best way to handle the database connection.
Most examples show the connection object being created in the example class, or even in each method. But it feels wrong to me to reference a connection string in every clss, even if it's pulling from the web.config.
My experience has been with using a DbDataContext or DbContext with Linq to SQL or Entity Framework, so this is new to me.
How do I structure my web apps when using Dapper as my Data Access strategy?
Update: clarification from MarredCheese's comment:
"No need to use a using statement. Dapper will automatically open,
close, and dispose of the connection for you." That's not correct.
Dapper will automatically open closed connections, and it will
automatically close connections that it auto-opened, but it will not
automatically dispose of connections. Marc Gravell and Eric Lippert
both advocate using using with Dapper here.
Microsoft.AspNetCore.All: v2.0.3 | Dapper: v1.50.2
I am not sure if I am using the best practices correctly or not, but I am doing it this way, in order to handle multiple connection strings.
It's easy if you have only 1 connection string
Startup.cs
using System.Data;
using System.Data.SqlClient;
namespace DL.SO.Project.Web.UI
{
public class Startup
{
public IConfiguration Configuration { get; private set; }
// ......
public void ConfigureServices(IServiceCollection services)
{
// Read the connection string from appsettings.
string dbConnectionString = this.Configuration.GetConnectionString("dbConnection1");
// Inject IDbConnection, with implementation from SqlConnection class.
services.AddTransient<IDbConnection>((sp) => new SqlConnection(dbConnectionString));
// Register your regular repositories
services.AddScoped<IDiameterRepository, DiameterRepository>();
// ......
}
}
}
DiameterRepository.cs
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
public class DiameterRepository : IDiameterRepository
{
private readonly IDbConnection _dbConnection;
public DiameterRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public IEnumerable<Diameter> GetAll()
{
const string sql = #"SELECT * FROM TABLE";
// No need to use using statement. Dapper will automatically
// open, close and dispose the connection for you.
return _dbConnection.Query<Diameter>(sql);
}
// ......
}
}
Problems if you have more than 1 connection string
Since Dapper utilizes IDbConnection, you need to think of a way to differentiate different database connections.
I tried to create multiple interfaces, 'inherited' from IDbConnection, corresponding to different database connections, and inject SqlConnection with different database connection strings on Startup.
That failed because SqlConnection inherits from DbConnection, and DbConnection inplements not only IDbConnection but also Component class. So your custom interfaces won't be able to use just the SqlConnection implenentation.
I also tried to create my own DbConnection class that takes different connection string. That's too complicated because you have to implement all the methods from DbConnection class. You lost the help from SqlConnection.
What I end up doing
During Startup, I loaded all connection string values into a dictionary. I also created an enum for all the database connection names to avoid magic strings.
I injected the dictionary as Singleton.
Instead of injecting IDbConnection, I created IDbConnectionFactory and injected that as Transient for all repositories. Now all repositories take IDbConnectionFactory instead of IDbConnection.
When to pick the right connection? In the constructor of all repositories! To make things clean, I created repository base classes and have the repositories inherit from the base classes. The right connection string selection can happen in the base classes.
DatabaseConnectionName.cs
namespace DL.SO.Project.Domain.Repositories
{
public enum DatabaseConnectionName
{
Connection1,
Connection2
}
}
IDbConnectionFactory.cs
using System.Data;
namespace DL.SO.Project.Domain.Repositories
{
public interface IDbConnectionFactory
{
IDbConnection CreateDbConnection(DatabaseConnectionName connectionName);
}
}
DapperDbConenctionFactory - my own factory implementation
namespace DL.SO.Project.Persistence.Dapper
{
public class DapperDbConnectionFactory : IDbConnectionFactory
{
private readonly IDictionary<DatabaseConnectionName, string> _connectionDict;
public DapperDbConnectionFactory(IDictionary<DatabaseConnectionName, string> connectionDict)
{
_connectionDict = connectionDict;
}
public IDbConnection CreateDbConnection(DatabaseConnectionName connectionName)
{
string connectionString = null;
if (_connectDict.TryGetValue(connectionName, out connectionString))
{
return new SqlConnection(connectionString);
}
throw new ArgumentNullException();
}
}
}
Startup.cs
namespace DL.SO.Project.Web.UI
{
public class Startup
{
// ......
public void ConfigureServices(IServiceCollection services)
{
var connectionDict = new Dictionary<DatabaseConnectionName, string>
{
{ DatabaseConnectionName.Connection1, this.Configuration.GetConnectionString("dbConnection1") },
{ DatabaseConnectionName.Connection2, this.Configuration.GetConnectionString("dbConnection2") }
};
// Inject this dict
services.AddSingleton<IDictionary<DatabaseConnectionName, string>>(connectionDict);
// Inject the factory
services.AddTransient<IDbConnectionFactory, DapperDbConnectionFactory>();
// Register your regular repositories
services.AddScoped<IDiameterRepository, DiameterRepository>();
// ......
}
}
}
DiameterRepository.cs
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
// Move the responsibility of picking the right connection string
// into an abstract base class so that I don't have to duplicate
// the right connection selection code in each repository.
public class DiameterRepository : DbConnection1RepositoryBase, IDiameterRepository
{
public DiameterRepository(IDbConnectionFactory dbConnectionFactory)
: base(dbConnectionFactory) { }
public IEnumerable<Diameter> GetAll()
{
const string sql = #"SELECT * FROM TABLE";
// No need to use using statement. Dapper will automatically
// open, close and dispose the connection for you.
return base.DbConnection.Query<Diameter>(sql);
}
// ......
}
}
DbConnection1RepositoryBase.cs
using System.Data;
using DL.SO.Project.Domain.Repositories;
namespace DL.SO.Project.Persistence.Dapper
{
public abstract class DbConnection1RepositoryBase
{
public IDbConnection DbConnection { get; private set; }
public DbConnection1RepositoryBase(IDbConnectionFactory dbConnectionFactory)
{
// Now it's the time to pick the right connection string!
// Enum is used. No magic string!
this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection1);
}
}
}
Then for other repositories that need to talk to the other connections, you can create a different repository base class for them.
using System.Data;
using DL.SO.Project.Domain.Repositories;
namespace DL.SO.Project.Persistence.Dapper
{
public abstract class DbConnection2RepositoryBase
{
public IDbConnection DbConnection { get; private set; }
public DbConnection2RepositoryBase(IDbConnectionFactory dbConnectionFactory)
{
this.DbConnection = dbConnectionFactory.CreateDbConnection(DatabaseConnectionName.Connection2);
}
}
}
using Dapper;
using System.Data;
namespace DL.SO.Project.Persistence.Dapper.Repositories
{
public class ParameterRepository : DbConnection2RepositoryBase, IParameterRepository
{
public ParameterRepository (IDbConnectionFactory dbConnectionFactory)
: base(dbConnectionFactory) { }
public IEnumerable<Parameter> GetAll()
{
const string sql = #"SELECT * FROM TABLE";
return base.DbConnection.Query<Parameter>(sql);
}
// ......
}
}
Hope all these help.
It was asked about 4 years ago... but anyway, maybe the answer will be useful to someone here:
I do it like this in all the projects.
First, I create a base class which contains a few helper methods like this:
public class BaseRepository
{
protected T QueryFirstOrDefault<T>(string sql, object parameters = null)
{
using (var connection = CreateConnection())
{
return connection.QueryFirstOrDefault<T>(sql, parameters);
}
}
protected List<T> Query<T>(string sql, object parameters = null)
{
using (var connection = CreateConnection())
{
return connection.Query<T>(sql, parameters).ToList();
}
}
protected int Execute(string sql, object parameters = null)
{
using (var connection = CreateConnection())
{
return connection.Execute(sql, parameters);
}
}
// Other Helpers...
private IDbConnection CreateConnection()
{
var connection = new SqlConnection(...);
// Properly initialize your connection here.
return connection;
}
}
And having such a base class I can easily create real repositories without any boilerplate code:
public class AccountsRepository : BaseRepository
{
public Account GetById(int id)
{
return QueryFirstOrDefault<Account>("SELECT * FROM Accounts WHERE Id = #Id", new { id });
}
public List<Account> GetAll()
{
return Query<Account>("SELECT * FROM Accounts ORDER BY Name");
}
// Other methods...
}
So all the code related to Dapper, SqlConnection-s and other database access stuff is located in one place (BaseRepository). All real repositories are clean and simple 1-line methods.
I hope it will help someone.
I created extension methods with a property that retrieves the connection string from configuration. This lets the callers not have to know anything about the connection, whether it's open or closed, etc. This method does limit you a bit since you're hiding some of the Dapper functionality, but in our fairly simple app it's worked fine for us, and if we needed more functionality from Dapper we could always add a new extension method that exposes it.
internal static string ConnectionString = new Configuration().ConnectionString;
internal static IEnumerable<T> Query<T>(string sql, object param = null)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
return conn.Query<T>(sql, param);
}
}
internal static int Execute(string sql, object param = null)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
return conn.Execute(sql, param);
}
}
I do it like this:
internal class Repository : IRepository {
private readonly Func<IDbConnection> _connectionFactory;
public Repository(Func<IDbConnection> connectionFactory)
{
_connectionFactory = connectionFactory;
}
public IWidget Get(string key) {
using(var conn = _connectionFactory())
{
return conn.Query<Widget>(
"select * from widgets with(nolock) where widgetkey=#WidgetKey", new { WidgetKey=key });
}
}
}
Then, wherever I wire-up my dependencies (ex: Global.asax.cs or Startup.cs), I do something like:
var connectionFactory = new Func<IDbConnection>(() => {
var conn = new SqlConnection(
ConfigurationManager.ConnectionStrings["connectionString-name"];
conn.Open();
return conn;
});
Best practice is a real loaded term. I like a DbDataContext style container like Dapper.Rainbow promotes. It allows you to couple the CommandTimeout, transaction and other helpers.
For example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Dapper;
// to have a play, install Dapper.Rainbow from nuget
namespace TestDapper
{
class Program
{
// no decorations, base class, attributes, etc
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? LastPurchase { get; set; }
}
// container with all the tables
class MyDatabase : Database<MyDatabase>
{
public Table<Product> Products { get; set; }
}
static void Main(string[] args)
{
var cnn = new SqlConnection("Data Source=.;Initial Catalog=tempdb;Integrated Security=True");
cnn.Open();
var db = MyDatabase.Init(cnn, commandTimeout: 2);
try
{
db.Execute("waitfor delay '00:00:03'");
}
catch (Exception)
{
Console.WriteLine("yeah ... it timed out");
}
db.Execute("if object_id('Products') is not null drop table Products");
db.Execute(#"create table Products (
Id int identity(1,1) primary key,
Name varchar(20),
Description varchar(max),
LastPurchase datetime)");
int? productId = db.Products.Insert(new {Name="Hello", Description="Nothing" });
var product = db.Products.Get((int)productId);
product.Description = "untracked change";
// snapshotter tracks which fields change on the object
var s = Snapshotter.Start(product);
product.LastPurchase = DateTime.UtcNow;
product.Name += " World";
// run: update Products set LastPurchase = #utcNow, Name = #name where Id = #id
// note, this does not touch untracked columns
db.Products.Update(product.Id, s.Diff());
// reload
product = db.Products.Get(product.Id);
Console.WriteLine("id: {0} name: {1} desc: {2} last {3}", product.Id, product.Name, product.Description, product.LastPurchase);
// id: 1 name: Hello World desc: Nothing last 12/01/2012 5:49:34 AM
Console.WriteLine("deleted: {0}", db.Products.Delete(product.Id));
// deleted: True
Console.ReadKey();
}
}
}
Try this:
public class ConnectionProvider
{
DbConnection conn;
string connectionString;
DbProviderFactory factory;
// Constructor that retrieves the connectionString from the config file
public ConnectionProvider()
{
this.connectionString = ConfigurationManager.ConnectionStrings[0].ConnectionString.ToString();
factory = DbProviderFactories.GetFactory(ConfigurationManager.ConnectionStrings[0].ProviderName.ToString());
}
// Constructor that accepts the connectionString and Database ProviderName i.e SQL or Oracle
public ConnectionProvider(string connectionString, string connectionProviderName)
{
this.connectionString = connectionString;
factory = DbProviderFactories.GetFactory(connectionProviderName);
}
// Only inherited classes can call this.
public DbConnection GetOpenConnection()
{
conn = factory.CreateConnection();
conn.ConnectionString = this.connectionString;
conn.Open();
return conn;
}
}
Everyone appears to be opening their connections entirely too early? I had this same question, and after digging through the Source here - https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper/SqlMapper.cs
You will find that every interaction with the database checks the connection to see if it is closed, and opens it as necessary. Due to this, we simply utilize using statements like above without the conn.open(). This way the connection is opened as close to the interaction as possible. If you notice, it also immediately closes the connection. This will also be quicker than it closing automatically during disposal.
One of the many examples of this from the repo above:
private static int ExecuteCommand(IDbConnection cnn, ref CommandDefinition command, Action<IDbCommand, object> paramReader)
{
IDbCommand cmd = null;
bool wasClosed = cnn.State == ConnectionState.Closed;
try
{
cmd = command.SetupCommand(cnn, paramReader);
if (wasClosed) cnn.Open();
int result = cmd.ExecuteNonQuery();
command.OnCompleted();
return result;
}
finally
{
if (wasClosed) cnn.Close();
cmd?.Dispose();
}
}
Below is a small example of how we use a Wrapper for Dapper called the DapperWrapper. This allows us to wrap all of the Dapper and Simple Crud methods to manage connections, provide security, logging, etc.
public class DapperWrapper : IDapperWrapper
{
public IEnumerable<T> Query<T>(string query, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
using (var conn = Db.NewConnection())
{
var results = conn.Query<T>(query, param, transaction, buffered, commandTimeout, commandType);
// Do whatever you want with the results here
// Such as Security, Logging, Etc.
return results;
}
}
}
I wrap connection with the helper class:
public class ConnectionFactory
{
private readonly string _connectionName;
public ConnectionFactory(string connectionName)
{
_connectionName = connectionName;
}
public IDbConnection NewConnection() => new SqlConnection(_connectionName);
#region Connection Scopes
public TResult Scope<TResult>(Func<IDbConnection, TResult> func)
{
using (var connection = NewConnection())
{
connection.Open();
return func(connection);
}
}
public async Task<TResult> ScopeAsync<TResult>(Func<IDbConnection, Task<TResult>> funcAsync)
{
using (var connection = NewConnection())
{
connection.Open();
return await funcAsync(connection);
}
}
public void Scope(Action<IDbConnection> func)
{
using (var connection = NewConnection())
{
connection.Open();
func(connection);
}
}
public async Task ScopeAsync<TResult>(Func<IDbConnection, Task> funcAsync)
{
using (var connection = NewConnection())
{
connection.Open();
await funcAsync(connection);
}
}
#endregion Connection Scopes
}
Examples of usage:
public class PostsService
{
protected IConnectionFactory Connection;
// Initialization here ..
public async Task TestPosts_Async()
{
// Normal way..
var posts = Connection.Scope(cnn =>
{
var state = PostState.Active;
return cnn.Query<Post>("SELECT * FROM [Posts] WHERE [State] = #state;", new { state });
});
// Async way..
posts = await Connection.ScopeAsync(cnn =>
{
var state = PostState.Active;
return cnn.QueryAsync<Post>("SELECT * FROM [Posts] WHERE [State] = #state;", new { state });
});
}
}
So I don't have to explicitly open the connection every time.
Additionally, you can use it this way for the convenience' sake of the future refactoring:
var posts = Connection.Scope(cnn =>
{
var state = PostState.Active;
return cnn.Query<Post>($"SELECT * FROM [{TableName<Post>()}] WHERE [{nameof(Post.State)}] = #{nameof(state)};", new { state });
});
What is TableName<T>() can be found in this answer.
Hi #donaldhughes I'm new on it too, and I use to do this:
1 - Create a class to get my Connection String
2 - Call the connection string class in a Using
Look:
DapperConnection.cs
public class DapperConnection
{
public IDbConnection DapperCon {
get
{
return new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ToString());
}
}
}
DapperRepository.cs
public class DapperRepository : DapperConnection
{
public IEnumerable<TBMobileDetails> ListAllMobile()
{
using (IDbConnection con = DapperCon )
{
con.Open();
string query = "select * from Table";
return con.Query<TableEntity>(query);
}
}
}
And it works fine.
Related
I have an architecture where multiple repository classes implement different queries and commands that are run against the database. I would like to separate the concern of "connecting to the database" + "running queries" and "providing a query to run" + "treating the result". I've written a Connection class that is then passed as a constructor argument to the repositories like such:
public class PostgreSqlConnection
{
private string connectionString;
public PostgreSqlConnection(string connectionString)
{
this.connectionString = connectionString;
}
public async Task<NpgsqlDataReader> ExecuteQueryCommand(NpgsqlCommand command)
{
using NpgsqlConnection connection = new NpgsqlConnection(this.connectionString);
await connection.OpenAsync();
command.Connection = connection;
command.Prepare();
return await command.ExecuteReaderAsync();
}
public async Task ExecuteNonQueryCommand(NpgsqlCommand command)
{
using NpgsqlConnection connection = new NpgsqlConnection(this.connectionString);
await connection.OpenAsync();
command.Connection = connection;
command.Prepare();
await command.ExecuteNonQueryAsync();
}
}
The instantiation would look something like this:
PostgreSqlConnection connection = new PostgreSqlConnection("...connection string");
IRepositoryA repA = new PostgreSqlRepositoryA(connection);
IRepositoryB repB = new PostgreSqlRepositoryB(connection);
Code duplication aside, this doesn't work since in the query case, the connection would be disposed of at the end of the ExecuteQueryCommand method and the reader would stop working.
Removing the using statement would fix this but from what I gather that is not good practice. Writing a Dispose / Disconnect method that I could call in the repositories would be something that would also work but it's not the repository's job to dispose of the connection.
How could I go about keeping the concerns separated and disposing of the items properly?
I think what here can help is a Unit of Work pattern. Basically, with UnitOfWork class you handle the connection, repository instances and transactions if needed (in case you are saving data to DB). You also have a flexibility to open a connection/transaction and then execute multiple commands across many repositories and in the end you either commit or rollback the transaction, or in case of pure reading you just close the connection using IDisposable pattern.
UnitOfWork class will handle the connection part, your BaseRepository (abstract class) will have your generic execute methods and it will handle the execution of query/command. The concrete repositories (A and B in your case) will inherit from BaseRepository, just prepare the commands/queries and call the Execute methods from a BaseRepository. Their responsibility is basically to prepare the query/command and to handle the result from Execute methods.
Please review the code because I don't have Postgres database and I can't test it 100%. I hope this is enough for you to give you a direction and the main idea behind the approach.
Here is the idea:
Implement UnitOfWork where you manange the connection, transaction if needed and repository instances.
public class UnitOfWork : IDisposable
{
private PostgreSqlRepositoryA _postgreSqlRepositoryA;
private PostgreSqlRepositoryB _postgreSqlRepositoryB;
private NpgsqlConnection _sqlConnection;
private NpgsqlTransaction _sqlTransaction;
private bool _disposed;
public UnitOfWork(string connectionString, bool withTransaction)
{
_sqlConnection = new NpgsqlConnection(connectionString);
_sqlConnection.Open();
if (withTransaction)
_sqlTransaction = _sqlConnection.BeginTransaction();
}
public PostgreSqlRepositoryA PostgreSqlRepositoryA
{
get
{
if(_postgreSqlRepositoryA == null)
{
_postgreSqlRepositoryA = new PostgreSqlRepositoryA(_sqlConnection);
}
return _postgreSqlRepositoryA;
}
}
public PostgreSqlRepositoryB PostgreSqlRepositoryB
{
get
{
if (_postgreSqlRepositoryB == null)
{
_postgreSqlRepositoryB = new PostgreSqlRepositoryB(_sqlConnection);
}
return _postgreSqlRepositoryB;
}
}
public void Commit()
{
// hanlde using try-catch
if(_sqlTransaction != null)
{
_sqlTransaction.Commit();
}
}
public void Rollback()
{
if (_sqlTransaction != null)
{
_sqlTransaction.Rollback();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (_sqlTransaction != null)
{
_sqlTransaction.Rollback(); // or throw an Exception for an opened transaction
}
if (_sqlConnection != null)
{
_sqlConnection.Close();
_sqlConnection.Dispose();
}
this._disposed = true;
}
}
}
Then what you need is a BaseRepository which will hold your "generic" methods for query/command execution:
public abstract class BaseRepository
{
protected NpgsqlConnection _sqlConnection;
public BaseRepository(NpgsqlConnection sqlConnection)
{
this._sqlConnection = sqlConnection;
}
public async Task<NpgsqlDataReader> ExecuteQueryCommand(NpgsqlCommand command)
{
command.Connection = _sqlConnection;
command.Prepare();
return await command.ExecuteReaderAsync();
}
public async Task ExecuteNonQueryCommand(NpgsqlCommand command)
{
command.Connection = _sqlConnection;
command.Prepare();
await command.ExecuteNonQueryAsync();
}
}
Your concrete repository implementation will look like this (I didn't bother with handling the reader, you can add that part):
public class PostgreSqlRepositoryB : BaseRepository
{
public PostgreSqlRepositoryB(NpgsqlConnection sqlConnection)
: base(sqlConnection)
{}
public async Task<int> GetCountB()
{
using (var sqlCommand = new NpgsqlCommand())
{
sqlCommand.CommandText = "select count(1) from TableB";
var reader = await ExecuteQueryCommand(sqlCommand);
// TODO: handle reader
}
}
}
And the in the end you will use it from your service or client method like this (if your are just reading from DB then set withTransaction to false, you don't need a transaction in that case):
using(var uow = new UnitOfWork("place_your_conn_string", withTransaction: true))
{
var countB = await uow.PostgreSqlRepositoryB.GetCountB();
uow.PostgreSqlRepositoryB.SaveSomethingToA("123456");
uow.Commit();
}
I am using asp.net core 2.0 and dapper. I have a class that wraps an IDbConnection Interface and only exposes certain methods. Here is a short version of that class.
public class MyConnectionString : IMyConnectionString
{
private readonly IDbConnection _connection;
public int ConnectionTimeout => _connection.ConnectionTimeout;
public string Database => _connection.Database;
public string ConnectionString { get => null; set => _connection.ConnectionString = value; }
public ConnectionState State => _connection.State;
public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper)
{
var con = "some logic to get the connection string.";
_connection = new SqlConnection(con);
}
public int Execute(string query, object parameters = null)
{
using (var con = _connection) { return con.Execute(query, parameters); }
}
}
I am injecting this class via a constructor to my Repository services. For example, this is a method that would call it:
internal class SomeRepository
{
private readonly IMyConnectionString _connection;
public SomeRepository(IMyConnectionString connection)
{
_connection = connection;
}
public void ExecuteSomeQuery(Object params)
{
var query = "Some query...";
_connection.Execute(query, params);
}
}
Now the problem is that if I call _connection.Execute(query, params); twice in a single request (2 different services), the second time it gets called the ConnectionString value inside MyConnectionString class is empty. I have tried binding it in Transient and Request scope to see if it would preserve it, but no luck. Any idea on why this is happening or how can I preserve it so that I won't have to create the connection string every time it is requested?
wrapping the Connection inside a using disposes the Connection at his end of execution: just as #Jasen said in comments.
I would, in your case, just get the connection and execute on the Connection created in the constructor: removing the using completely.
You should not create the SqlConnection, since you are implementing dependency injection. You should:
Implement IDisposable to dispose your connection when your class is collected.
Pass a SqlConnection factory to create your SqlConnection, seperating your creation logic from your class.
Your class should resemble something like this:
public class MyConnectionString : IMyConnectionString
{
private readonly IDbConnection _connection;
public int ConnectionTimeout => _connection.ConnectionTimeout;
public string Database => _connection.Database;
public string ConnectionString
{
get => null;
set => _connection.ConnectionString = value;
}
public ConnectionState State => _connection.State;
public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper)
{
string con = "some logic to get the connection string.";
_connection = new SqlConnection(con);
}
public int Execute(string query, object parameters = null)
{
return _connection.Execute(query, parameters);
}
}
With IDisposable implementation:
using System;
public class MyConnectionString : IMyConnectionString, IDisposable
{
private readonly IDbConnection _connection;
public int ConnectionTimeout => _connection.ConnectionTimeout;
public string Database => _connection.Database;
public string ConnectionString
{
get => null;
set => _connection.ConnectionString = value;
}
public ConnectionState State => _connection.State;
public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper)
{
string con = "some logic to get the connection string.";
_connection = new SqlConnection(con);
}
public int Execute(string query, object parameters = null)
{
return _connection.Execute(query, parameters);
}
public void Dispose()
{
_connection.Dispose();
}
}
With your own ISqlConnectionFactory factory:
public class MyConnectionString : IMyConnectionString, IDisposable
{
private readonly IDbConnection _connection;
private readonly ISqlConnectionFactory _factory;
public int ConnectionTimeout => _connection.ConnectionTimeout;
public string Database => _connection.Database;
public string ConnectionString
{
get => null;
set => _connection.ConnectionString = value;
}
public ConnectionState State => _connection.State;
public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper, ISqlConnectionFactory factory)
{
_factory = factory;
_connection = _factory.CreateConnection(connProvOpts, encHelper);
}
public int Execute(string query, object parameters = null)
{
return _connection.Execute(query, parameters);
}
}
public interface ISqlConnectionFactory
{
SqlConnection CreateConnection(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper);
}
public class SqlConnectionFactory : ISqlConnectionFactory
{
public SqlConnectionFactory()
{
// Maybe initialization?
}
public SqlConnection CreateConnection(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper)
{
string con = "some logic to get the connection string.";
_connection = new SqlConnection(con);
}
}
Personally, I would have created and disposed the Connection each time Execute is invoked. This means that outside of Execute, your connection is closed and resources are released.
We are currently using dapper ORM to access data by calling store procedures. The current code is having a class BusinessFunctions which inherits another class DataFunctions which are having helper methods to execute the stored procedures.
I am not happy with this code. It's just too rigid and not future proof. And above all it's not coded to an interface rather coded to an implementation. I propose an interface IRepository with an abstract class Repository which implements all helper generic methods. Then I create BusinessRepository that implements the abstract Repository class and call the generic helpers method. Again, my colleague is telling me to remove the IRepository interface and just use the Repository abstract class.
public class BusinessFunctions : DataFunctions
{
public BusinessFunctions(ConnectionManager conMgr, LogWriter logWriter, AppUser appUser) : base(conMgr, logWriter, appUser)
{
}
public async Task<Business> FindAsync(int businessId)
{
throw new NotImplementedException();
}
public async Task<Business> FindAsync(string businessGuid)
{
var lst = await StoredProcQueryAsync<Business>("spBusinessGetSetupGUID", new { BusinessGuid = businessGuid });
if (lst.Count() == 0)
throw new NotFoundInDatabaseException("Business", businessGuid);
else
return lst.Single();
}
public async Task<bool> IsHostedTokenizeCardAllowedAsync(string businessGuid)
{
var b = await FindAsync(businessGuid);
if (b.HostedPaymentEnabled)
return true;
else
return false;
}
}
public class DataFunctions : IDisposable
{
private ConnectionManager _conMgr;
private LogWriter _logWriter;
private AppUser _appUser;
public ConnectionManager ConnMgr
{
get { return _conMgr; }
}
protected LogWriter Logger
{
get { return _logWriter; }
}
protected AppUser User
{
get { return _appUser; }
}
public DataFunctions(ConnectionManager conMgr, LogWriter logWriter, AppUser appUser)
{
_conMgr = conMgr;
_logWriter = logWriter;
_appUser = appUser;
}
public void Dispose()
{
}
public async Task StoredProcExecuteNonQueryAsync(string storedProc,
List<StoredProcParameter> storedProcParameters = null,
SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default,
SqlAccessType accessType = SqlAccessType.ReadWrite
)
{
using (SqlConnection conn = new SqlConnection(ConnMgr.SqlConnectionString))
{
await conn.OpenAsync();
await StoredProcExecuteNonQueryAsync(conn,
storedProc,
storedProcParameters: storedProcParameters,
commandTimeout: commandTimeout,
accessType: accessType);
}
}
public async Task StoredProcExecuteNonQueryAsync(SqlConnection conn,
string storedProc,
List<StoredProcParameter> storedProcParameters = null,
SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default,
SqlAccessType accessType = SqlAccessType.ReadWrite,
SqlTransaction trans = null
)
{
using (SqlCommand cmd = new SqlCommand(storedProc, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = (int)commandTimeout;
if (trans != null) cmd.Transaction = trans;
if (storedProcParameters != null)
{
foreach(var p in storedProcParameters)
{
cmd.Parameters.Add(p.ToSqlParameter());
}
}
await cmd.ExecuteNonQueryAsync();
}
}
public async Task<IEnumerable<T>> StoredProcQueryAsync<T>(string storedProc,
object storedProcParameters = null,
SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default,
SqlAccessType accessType = SqlAccessType.ReadWrite)
{
using (SqlConnection conn = new SqlConnection(ConnMgr.SqlConnectionString))
{
conn.Open();
return await StoredProcQueryAsync<T>(conn,
storedProc,
storedProcParameters,
commandTimeout);
}
}
public async Task<IEnumerable<T>> StoredProcQueryAsync<T>(SqlConnection conn,
string storedProc,
object storedProcParameters = null,
SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default)
{
return await conn.QueryAsync<T>(storedProc,
commandType: CommandType.StoredProcedure,
commandTimeout: (int)commandTimeout,
param: storedProcParameters);
}
}
I think the reason you're unhappy with the code is that it seems to be intermingling service functionality into the repository layer. The repository layer should simply call the stored procedure.
public async Task<bool> IsHostedTokenizeCardAllowedAsync(string businessGuid)
{
var b = await FindAsync(businessGuid);
if (b.HostedPaymentEnabled)
return true;
else
return false;
}
This for example is a good candidate to be in the service layer.
Your repo layer should really just have your ConnectionManager or a Connection factory injected via IoC.
The trick we use is to put an attribute on data model fields that we know are going to be stored procedure parameters (usually most or all). Then we have an extension method that reflects over the attributes and pulls the fields, values, and types creating a dapper DynamicParameters object. Most of our repository calls look like this:
public async Task<User> AddUserAsync(UserAdd user)
{
using (var connection = _connectionFactory.Create()
{
var result = connection.ExecuteAsync("dbo.AddUser", user.GetParameters(), commandType: CommandType.StoredProcedure";
return result;
}
}
It's relatively quick and easy to use. Gets are very easy to test. Inserts/Deletes/Updates not so much. You get into needing to mock the SqlConnection which can be problematic.
In addition, if you get into more complex areas that are subject to change, you can use the strategy pattern to move methods into their own classes. Below would be an example of splitting your add method into its own class:
public class MyRepository
{
private readonly IAddMethod<UserAdd> _addMethod;
private readonly IConnectionFactory _connectionFactory;
public MyRepository(IAddMethod<UserAdd> userAddMethod,
IConnectionFactory connectionFactory)
{
//..guard clauses, assignments, etc.
}
public async Task<int> AddAsync(UserAdd user)
{
return _addMethod.AddAsync(user);
}
}
You can even decorate these strategy methods in IoC to hide/augment them as needed. (in structuremap it's .DecorateAllWith()
In short, move any logic to the service layer, consider a generic extension method for creating your DynamicParameters list, and inject the connection factory via IoC. I think you'll find the separation of concerns will simplify things significantly.
Code bellow will create eventstore for named connection.
var es = Wireup.Init()
.UsingSqlPersistence("DB")
.Build();
I need something like:
var es = Wireup.Init()
.UsingSqlPersistence("Data Source=TEST;Initial Catalog=App")
.Build();
The most easy way I found is to create custom IConnectionFactory, but this does not look right. Any suggestions?
I did not find a way to do it with any of the built-in classes, but there is the interface you mentioned with is more or less easy to use.
Using joliver's code I implemented a Connection String factory as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Configuration;
using System.Data;
using EventStore.Persistence.SqlPersistence;
using EventStore.Persistence;
namespace Project.Factories
{
public class ConnectionStringConnectionFactory : IConnectionFactory
{
private static readonly IDictionary<string, DbProviderFactory> CachedFactories =
new Dictionary<string, DbProviderFactory>();
private string m_connectionString;
private string m_providerName;
private string m_replicaConnectionString;
private string m_replicaProviderName;
public ConnectionStringConnectionFactory(string connectionString, string providerName)
: this(connectionString, providerName, connectionString, providerName)
{
}
public ConnectionStringConnectionFactory(
string connectionString,
string providerName,
string replicaConnectionString,
string replicaProviderName)
{
m_connectionString = connectionString;
m_providerName = providerName;
m_replicaConnectionString = replicaConnectionString;
m_replicaProviderName = replicaProviderName;
}
public virtual IDbConnection OpenMaster(Guid streamId)
{
return this.Open(streamId, m_connectionString, m_providerName);
}
public virtual IDbConnection OpenReplica(Guid streamId)
{
return this.Open(streamId, m_replicaConnectionString, m_replicaProviderName);
}
protected virtual IDbConnection Open(Guid streamId, string connectionString, string providerName)
{
return new ConnectionScope(connectionString, () => this.Open(connectionString, providerName));
}
protected virtual IDbConnection Open(string connectionString, string providerName)
{
var factory = this.GetFactory(providerName);
var connection = factory.CreateConnection();
if (connection == null)
throw new ConfigurationErrorsException("Invalid provider name");
connection.ConnectionString = connectionString;
try
{
connection.Open();
}
catch (Exception e)
{
throw new StorageUnavailableException(e.Message, e);
}
return connection;
}
protected virtual DbProviderFactory GetFactory(string providerName)
{
lock (CachedFactories)
{
DbProviderFactory factory;
if (CachedFactories.TryGetValue(providerName, out factory))
return factory;
factory = DbProviderFactories.GetFactory(providerName);
return CachedFactories[providerName] = factory;
}
}
public ConnectionStringSettings Settings
{
get { return new ConnectionStringSettings("Default", m_connectionString, m_providerName); }
}
}
}
To use it simply pass in a factory:
var fac = new ConnectionStringConnectionFactory(
"Your Connection String",
"System.Data.SqlClient");
Wireup.Init().UsingSqlPersistence(fac)
If you wanted you could wrap that in an extension method:
Wireup.Init().UsingSqlPersistenceWithConnectionString("")
Created a pull request for supporting configuration with connection string.
https://github.com/NEventStore/NEventStore/pull/358
If not accepted, you can still use the code to enable configuration with connection string in your own project, it's only a few lines of code.
UPDATE: Pull request is accepted, and is available as of version 5.1 of NEventstore. Which is now available on nuget.
I would like to use Entity Framework Code first approach with SQLCE4 database. Everything seems to be really nice but I have problem with debugging sql queries. I found that EFTracing from http://efwrappers.codeplex.com/ should be exactly what I need but I don't know how to use it without app.config file. I am not big fan of this configuration. I want to use only C# code to set everything up and running. I think it should be fine to use code like this:
using (System.Data.Common.DbConnection c =
new EFTracingProvider.EFTracingConnection(
new System.Data.SqlServerCe.SqlCeConnection(conn)))
{
using (var context = new MyContext(c))
{
var a = from data in context.Projects select data;
}
}
But it doesn't work. It throws exception:
Unable to determine the provider name for connection of type
EFTracingProvider.EFTracingConnection'.
Is there any simple way how to correctly create wrapped connection only in code?
Solution for my problem is following DbContext object.
public class MyContext : DbContext
{
public MyContext()
: base(CreateConnection("Data Source=file.sdf",
"System.Data.SqlServerCe.4.0"), true)
{ }
public DbSet<Project> Projects { get; set; }
public static bool TraceEnabled = true;
private static DbConnection CreateConnection(string connectionString,
string providerInvariantName)
{
DbConnection connection = null;
if (TraceEnabled)
{
EFTracingProviderConfiguration.RegisterProvider();
EFTracingProviderConfiguration.LogToConsole = true;
string wrapperConnectionString = String.Format(#"wrappedProvider={0};{1}",
providerInvariantName, connectionString);
connection = new EFTracingConnection()
{
ConnectionString = wrapperConnectionString
};
}
else
{
DbProviderFactory factory = DbProviderFactories.GetFactory(providerInvariantName);
connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
}
return connection;
}
}
So now I can use just context and connection is created automatically for wrapped or unwrapped SqlCe depending on TraceEnabled property.
using (var context = new MyContext())
{
var a = context.Projects.FirstOrDefault();
}
The genuine way to trace SQL queries is to call the ToString method like that :
var t = from c in _entities.CompanyDetail
select c;
string test = t.ToString();
I don't know EFTracing, but you might want to try MVCMiniProfiler. Despite the name MVCMiniProfiler also provide SQL queries profiling and work without config file.
I've done this by creating a wrapper class around the ObjectContext and using that wrapper instead of the original context. Here's an example context wrapper:
public partial class LoggedContext : MyContext
{
public LoggedContext()
: this("name=MyEntities") // Adjust this to match your entities
{
}
public LoggedContext(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(connectionString)
{
}
private EFTracingConnection TracingConnection
{
get { return this.UnwrapConnection<EFTracingConnection>(); }
}
public event EventHandler<CommandExecutionEventArgs> CommandExecuting
{
add { this.TracingConnection.CommandExecuting += value; }
remove { this.TracingConnection.CommandExecuting -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFinished
{
add { this.TracingConnection.CommandFinished += value; }
remove { this.TracingConnection.CommandFinished -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFailed
{
add { this.TracingConnection.CommandFailed += value; }
remove { this.TracingConnection.CommandFailed -= value; }
}
}
I also have a static class that defines the tracing output method and has a static method to initialize tracing. Here:
public static class EFTracingExtensions
{
private static ILogger _logger;
public static void InitSqlTracing(ILogger logger)
{
_logger = logger;
EFTracingProviderConfiguration.RegisterProvider();
if (logger.IsLoggingEnabled()) // Don't add logging hooks if logging isn't enabled
{
EFTracingProviderConfiguration.LogAction = new Action<CommandExecutionEventArgs>(AppendSqlLog);
}
}
private static void AppendSqlLog(CommandExecutionEventArgs e)
{
if (e.Status != CommandExecutionStatus.Executing) // we only care about Finished and Failed
{
StringBuilder msg = new StringBuilder(e.ToTraceString().TrimEnd());
msg.Append(Environment.NewLine);
if (e.Result is SqlDataReader)
{
int rows = ((SqlDataReader)e.Result).HasRows ? ((SqlDataReader)e.Result).RecordsAffected : 0;
msg.AppendFormat("*** {0} rows affected", rows);
}
else if (e.Result is int)
{
msg.AppendFormat("*** result: {0}", e.Result);
}
else
{
msg.AppendFormat("*** finished, result: {0}", e.Result);
}
msg.Append(Environment.NewLine);
msg.AppendFormat(" [{0}] [{1}] in {2} seconds", e.Method, e.Status, e.Duration);
_logger.Log(msg.ToString(), LoggerCategories.SQL);
}
}
}
ILogger is the logging interface I'm using. You need to substitute your own interface/methods.
The InitSqlTracing method is invoked once when my program starts up, and then the LoggedContext class is used to log all the SQL generated by Entity Framework.
Putting it all together with your sample code:
EFTracingExtensions.InitSqlTracing(logger); // only call this once
using (var context = new LoggedContext())
{
var a = from data in context.Projects select data;
}