Dapper - Get information about the executed query statement - c#

I replaced the MySQL.Data package with Dapper. To fetch one user from the database all I have to do now is
public Task<User> GetUser(string username)
{
using IDbConnection databaseConnection = new MySqlConnection("connectionString");
DynamicParameters parameters = new DynamicParameters();
parameters.Add("#username", username, DbType.String);
return databaseConnection.QueryFirstOrDefaultAsync<User>(
"SELECT * FROM person WHERE username = #username",
parameters);
}
but I would like to add some trace level logging. Is there a way I can fetch the query string before executing it?

Create your own IDbCommand which would wrap your real IDbCommand and log what you want to intercept.
But since Dapper creates the IDbCommand automatically, you also have to create your own IDbConnection (see CreateCommand below) which would wrap your real IDbConnection and in case would use your own IDbCommand.
Example:
/// <summary>
/// This is just a wrapper around IDbConnection,
/// which allows us to build a wrapped IDbCommand for logging/debugging
/// </summary>
public class InterceptedDbConnection : IDbConnection
{
private readonly IDbConnection _conn;
public InterceptedDbConnection(IDbConnection connection)
{
_conn = connection;
}
public string ConnectionString { get => _conn.ConnectionString; set => _conn.ConnectionString = value; }
public int ConnectionTimeout => _conn.ConnectionTimeout;
public string Database => _conn.Database;
public ConnectionState State => _conn.State;
public IDbTransaction BeginTransaction() => _conn.BeginTransaction();
public IDbTransaction BeginTransaction(IsolationLevel il) => _conn.BeginTransaction(il);
public void ChangeDatabase(string databaseName) => _conn.ChangeDatabase(databaseName);
public void Close() => _conn.Close();
public IDbCommand CreateCommand()
{
// Wrap real command under InterceptedDbCommand
IDbCommand underlyingCommand = _conn.CreateCommand();
return new InterceptedDbCommand(underlyingCommand);
// you could also save this into a "LastCommand" to expose it
// and explore parameter types that Dapper used
}
public void Dispose() => _conn.Dispose();
public void Open() => _conn.Open();
}
/// <summary>
/// This is just a wrapper around IDbCommand,
/// which allows us to log queries
/// or inspect how Dapper is passing our Parameters
/// </summary>
public class InterceptedDbCommand : IDbCommand
{
private readonly IDbCommand _cmd;
public InterceptedDbCommand(IDbCommand command)
{
_cmd = command;
}
public string CommandText { get => _cmd.CommandText; set => _cmd.CommandText = value; }
public int CommandTimeout { get => _cmd.CommandTimeout; set => _cmd.CommandTimeout = value; }
public CommandType CommandType { get => _cmd.CommandType; set => _cmd.CommandType = value; }
public IDbConnection Connection { get => _cmd.Connection; set => _cmd.Connection = value; }
public IDataParameterCollection Parameters => _cmd.Parameters;
public IDbTransaction Transaction { get => _cmd.Transaction; set => _cmd.Transaction = value; }
public UpdateRowSource UpdatedRowSource { get => _cmd.UpdatedRowSource; set => _cmd.UpdatedRowSource = value; }
public void Cancel() => _cmd.Cancel();
public IDbDataParameter CreateParameter() => _cmd.CreateParameter();
public void Dispose() => _cmd.Dispose();
public void Prepare() => _cmd.Prepare();
public int ExecuteNonQuery()
{
// TODO: Log _cmd.CommandText + _cmd.Parameters
return _cmd.ExecuteNonQuery();
}
public IDataReader ExecuteReader()
{
// TODO: Log _cmd.CommandText + _cmd.Parameters
return _cmd.ExecuteReader();
}
public IDataReader ExecuteReader(CommandBehavior behavior)
{
// TODO: Log _cmd.CommandText + _cmd.Parameters
return _cmd.ExecuteReader(behavior);
}
public object ExecuteScalar()
{
// TODO: Log _cmd.CommandText + _cmd.Parameters
return _cmd.ExecuteScalar();
}
}
Last, just replace your connection by the wrapped one:
IDbConnection databaseConnection = new InterceptedDbConnection(MySqlConnection("connectionString"));

Related

SQLite :memory: database usage with using / dispose

I have wrapped all of my SQL Connections in a using statement.
using (DbConnection dbConnection = GetConnection())
{
using (DbCommand dbCommand = dbConnection.CreateCommand(cmdInsert))
{
//some work
}
}
For UnitTests I supposed to use a :memory: database, but the database is automatically deleted, after closing the connection.
https://www.sqlite.org/inmemorydb.html
The database is automatically deleted and memory is reclaimed when the last connection to the database closes.
Is there a solution how to use a :memory: database and use using? I don't want to write exactly the same code twice without using..
Complete Example
Database
public abstract class SqliteBase
{
public string ConnectionString;
protected SqliteBase()
{
SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder
{
DataSource = ":memory:",
ForeignKeys = true,
DefaultTimeout = 3,
DateTimeKind = DateTimeKind.Utc,
Pooling = false
};
ConnectionString = builder.ConnectionString + ";mode=memory;cache=shared";
}
private DbConnection _MemoryConnection;
protected DbConnection GetConnection()
{
try
{
if (_MemoryConnection == null)
{
_MemoryConnection = new SQLiteConnection(ConnectionString);
_MemoryConnection.Open();
}
DbConnection dbConnection = new SQLiteConnection(ConnectionString);
dbConnection.Open();
return dbConnection;
}
catch (Exception ex)
{
throw new Exception("Error opening database connection.", ex);
}
}
/// <summary>
/// Creates a table in the SQL database if it does not exist
/// </summary>
/// <param name="tableName">The name of the table</param>
/// <param name="columns">Comma separated column names</param>
protected void CreateTable(string tableName, string columns)
{
using (DbConnection dbConnection = GetConnection())
{
using (DbCommand dbCommand = dbConnection.CreateCommand($"create table if not exists {tableName} ({columns})"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}
public class FooDatabase : SqliteBase
{
public FooDatabase()
{
CreateTable("FooTable", "Foo TEXT");
}
public void DoFoo()
{
using (DbConnection dbConnection = GetConnection())
{
using (DbCommand dbCommand = dbConnection.CreateCommand("Select * from FooTable"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}
Unit Test
public static class SQLiteTestSetup
{
public static FooDatabase ClassInit()
{
return new FooDatabase();
}
public static void Cleanup()
{
}
}
public abstract class SQLiteTestBase
{
public static FooDatabase Database { get; set; }
[TestMethod]
public void DoSomeFooTest()
{
Database.DoFoo();
}
}
[TestClass]
public class SQLiteTest : SQLiteTestBase
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
Database = SQLiteTestSetup.ClassInit();
}
[ClassCleanup]
public static void ClassCleanup() => SQLiteTestSetup.Cleanup();
}
Exception
Die Testmethode "....SQLiteTest.DoSomeFooTest" hat eine Ausnahme ausgelöst:
System.Data.SQLite.SQLiteException: SQL logic error
no such table: FooTable
bei System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn, String strSql, SQLiteStatement previous, UInt32 timeoutMS, String& strRemain)
bei System.Data.SQLite.SQLiteCommand.BuildNextCommand()
bei System.Data.SQLite.SQLiteCommand.GetStatement(Int32 index)
bei System.Data.SQLite.SQLiteDataReader.NextResult()
bei System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
bei System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
bei System.Data.SQLite.SQLiteCommand.ExecuteNonQuery(CommandBehavior behavior)
bei System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
bei ....FooDatabase.DoFoo() in ...\SqliteDatabaseBase.cs:Zeile 83.
bei ....SQLiteTestBase.DoSomeFooTest() in ...\SQLiteTest.cs:Zeile 30.
Working Solution approach
I have added a ConnectionContext class, where I can set a flag to decide if I want to dispose my DbConnection or not.
Database class
public class ConnectionContext : IDisposable
{
private readonly bool _ContextOwnsConnection;
public readonly DbConnection Connection;
public ConnectionContext(DbConnection connection, bool contextOwnsConnection)
{
Connection = connection;
_ContextOwnsConnection = contextOwnsConnection;
}
public void Dispose()
{
if(_ContextOwnsConnection)
Connection.Dispose();
}
}
public abstract class SqliteBase
{
public Func<ConnectionContext> GetContext;
private ConnectionContext _GetConnectionContext()
{
return new ConnectionContext(GetConnection(), true);
}
private string _ConnectionString;
private readonly string _Dbfile;
protected SqliteBase()
{
GetContext = _GetConnectionContext;
_Dbfile = ":memory:";
_InitConnectionString();
}
private void _InitConnectionString()
{
SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder
{
DataSource = _Dbfile,
ForeignKeys = true,
DefaultTimeout = 3,
DateTimeKind = DateTimeKind.Utc,
Pooling = true
};
_ConnectionString = builder.ConnectionString;
}
public DbConnection GetConnection()
{
try
{
DbConnection dbConnection = SQLiteFactory.Instance.CreateConnection();
dbConnection.ConnectionString = _ConnectionString;
dbConnection.Open();
return dbConnection;
}
catch (Exception ex)
{
throw new Exception("Error opening database connection.", ex);
}
}
/// <summary>
/// Creates a table in the SQL database if it does not exist
/// </summary>
/// <param name="tableName">The name of the table</param>
/// <param name="columns">Comma separated column names</param>
protected void CreateTable(string tableName, string columns)
{
using (ConnectionContext context = GetContext())
{
using (DbCommand dbCommand = context.Connection.CreateCommand($"create table if not exists {tableName} ({columns})"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}
public class FooDatabase : SqliteBase
{
public FooDatabase()
{
Initialize();
}
public void Initialize()
{
CreateTable("FooTable", "Foo TEXT");
}
public void DoFoo()
{
using (ConnectionContext context = GetContext())
{
using (DbCommand dbCommand = context.Connection.CreateCommand("Select * from FooTable"))
{
dbCommand.ExecuteNonQuery();
}
}
}
}
Unit Test
public abstract class SQLiteTestBase
{
public static ConnectionContext Connection { get; set; }
public static FooDatabase Database { get; set; }
[TestMethod]
public void DoSomeFooTest()
{
Database.DoFoo();
}
}
[TestClass]
public class SQLiteTest : SQLiteTestBase
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
Database = new FooDatabase();
Database.GetContext = () => Connection;
Connection = new ConnectionContext(Database.GetConnection(), false);
}
[TestInitialize]
public void TestInit()
{
Connection = new ConnectionContext(Database.GetConnection(), false);
Database.Initialize();
}
[TestCleanup]
public void TestCleanup()
{
Connection.Dispose();
Connection = null;
}
}
I guess you stopped reading to early. The second paragraph of the link you posted, "In-memory Databases And Shared Cache" describes what you can do and need to do in your case:
The database is deleted after closing the last connection if you use the method described in the link you posted.
You need a file URI and mode=memory for in-memory and cache=shared to have multiple connections go to the same named database.
So if your unit tests starts out with a using statement for a connection that is named (for example with the same name as your current test) then inside that using statement, all connections using the same connection string should connect to the same in-memory database.
I was having same issue with sharing in memory sqlite database. My solution was to set connection string to "FullUri=file::memory:?cache=shared"
Try adding a name for the datasource instead of :memory:
data source=testName;foreign keys=True;default timeout=3;datetimekind=Utc;pooling=False;mode=memory;cache=shared

ConnectionString lost on second execute

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.

Making an application Database Agnostic

I have an existing C# application, which I intend to make Database Agnostic, in such a way that the Database Engine is abstracted from the Business Logic completely.
Here is my approach to make one -
public abstract class DbEngine // I can also make it an Interface
{
}
public class SQLDBEngine : DbEngine
{
public bool ExecuteSP(string SPName)
{
}
public void ExecuteInlineQuery(String SQLQuery)
{
}
}
public class MySQLDBEngine : DbEngine
{
public bool ExecuteSP(string SPName)
{
}
public void ExecuteInlineQuery(String SQLQuery)
{
}
}
I then have a Factory class, which takes care of Instantiating the appropriate DbEngine object -
public class ConnectionManager
{
string CurrentEngine;
public ConnectionManager()
{
// Read from configuration file to know which database to configure
// Config returns wither MS or MY
// MS = SQLDBEngine
// MY = MYSQLDBEngine
}
public DbEngine GetDBInstance()
{
switch(CurrentEngine)
{
case "MS":
return new SQLDBEngine();
case "MY":
return new MySQLDBEngine();
default:
return new SQLDBEngine();
}
}
}
The Business Logic will only interact with the ConnectionManager object, thus abstracting the Database completely from it .
The Client will interact with the following code-
ConnectionManager conn = new ConnectionManager();
DBEngine obj = conn.GetDBInstance();
obj.ExecuteInlineQuery("select * from tblItems");
The Problem here, is that if the we introduce MongoDBEngine as the new database engine, this will require once more class MongoDBEngine - but since it doesn't have a Stored Procedure like feature, so ExecuteSP doesn't make sense and hence the Business Logic call will fail.
Iam just trying to encapsulate the Database Engine from the Business Logic, so that when the database is changed, the Business Logic should not undergo any change.
Is there any design pattern or technique that I could follow ?
Rather than trying to expose the functionality of the database to the application, you should abstract away the method of access. Instead of providing an ability to execute a query, embed that query or stored procedure call or insert/update/delete command as part of your repository class.
public class MySQLCustomerRepository : ICustomerRepository
{
private readonly string _connectionString;
public MySQLCustomerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate)
{
//open a MySQL connection and execute query to retrieve customer orders
}
}
public class MongoCustomerRepository : ICustomerRepository
{
private readonly string _connectionString;
public MongoCustomerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate)
{
//connect to mongo, get customers by running query
}
}
public interface ICustomerRepository
{
List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate);
}
The consuming application itself should have no knowledge of queries, because the repository itself takes care of those details.
Part of the point of this is that each database will have different queries and commands that make sense for it. An SQL query written for MS SQL may not be the same as one written for Oracle, and of course SQL won't work at all on a no-SQL database. So each implementation should be responsible for using the correct interactions for its corresponding database, and your consuming application shouldn't need to know how that works, because it should always access the database via an interface, never through a concrete implementation .
I think the last answer from mason is a really step forward through a good desing. I would go one step further in OO desing and try to think as an object page for a Dto and return a sequence of something. A change i would do is to encapsulate the parameters of the methods inside the object and inject them through constructor, so this way you will have multiple clases implementing an abstraction of your query(1 class for a paged sequence, other class for searching for id, start and end time, etc. The result will be the same return type) instead of a big monster with a bunch of methods returning the same type. This way you get better mantainability, so if you have a issue with a mongo class for a specific query, you check one tiny class and not a GOD class, here is some paging desing:
/// <summary>
/// DTO
/// </summary>
public class CustomerOrder
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Define a contract that get a sequence of something
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IFetch<T>
{
IEnumerable<T> Fetch();
}
/// <summary>
/// Define a pageTemplate
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class PageTemplate<T> : IFetch<T>
{
protected readonly int pageSize;
protected readonly int page;
public PageTemplate(int page, int pageSize)
{
this.page = page;
this.pageSize = pageSize;
}
public abstract IEnumerable<T> Fetch();
}
/// <summary>
/// Design a MyDto Page object, Here you are using the Template method
/// </summary>
public abstract class MyDtoPageTemplate : PageTemplate<CustomerOrder>
{
public MyDtoPageTemplate(int page, int pageSize) : base(page, pageSize) { }
}
/// <summary>
/// You can use ado.net for full performance or create a derivated class of MyDtoPageTemplate to use Dapper
/// </summary>
public sealed class SqlPage : MyDtoPageTemplate
{
private readonly string _connectionString;
public SqlPage(int page, int pageSize, string connectionString) : base(page, pageSize)
{
_connectionString = connectionString;
}
public override IEnumerable<CustomerOrder> Fetch()
{
using (var connection = new SqlConnection(_connectionString))
{
//This can be injected from contructor or encapsulated here, use a Stored procedure, is fine
string commandText = "Select Something";
using (var command = new SqlCommand(commandText, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
if (reader.HasRows) yield break;
while (reader.Read())
{
yield return new CustomerOrder()
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Value = reader.GetString(2)
};
}
}
}
}
}
}
public sealed class MongoDbPage : MyDtoPageTemplate
{
private readonly string _connectionString;
public MongoDbPage(int page, int pageSize, string connectionString) : base(page, pageSize)
{
_connectionString = connectionString;
}
public override IEnumerable<CustomerOrder> Fetch()
{
//Return From CustomerOrder from mongoDb
throw new NotImplementedException();
}
}
/// <summary>
/// You can test and mock the fetcher
/// </summary>
public sealed class TestPage : IFetch<CustomerOrder>
{
public IEnumerable<CustomerOrder> Fetch()
{
yield return new CustomerOrder() { Id = 0, Name = string.Empty, Value = string.Empty };
yield return new CustomerOrder() { Id = 1, Name = string.Empty, Value = string.Empty };
}
}
public class AppCode
{
private readonly IFetch<CustomerOrder> fetcher;
/// <summary>
/// From IoC, inject a fetcher object
/// </summary>
/// <param name="fetcher"></param>
public AppCode(IFetch<CustomerOrder> fetcher)
{
this.fetcher = fetcher;
}
public IEnumerable<CustomerOrder> FetchDtos()
{
return fetcher.Fetch();
}
}
public class CustomController
{
private readonly string connectionString;
public void RunSql()
{
var fetcher = new SqlPage(1, 10, connectionString);
var appCode = new AppCode(fetcher);
var dtos = appCode.FetchDtos();
}
public void RunTest()
{
var fetcher = new TestPage();
var appCode = new AppCode(fetcher);
var dtos = appCode.FetchDtos();
}
}

How do I handle Database Connections with Dapper in .NET?

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.

How to mock SqlParameterCollection using Moq

I am trying to mock database operations. I have problem in mocking SqlParameterCollection. I tried to create virtual method that will return DbParameterCollection but then i am loosing all the functionality that SqlParameterCollection gives like AddWithValue etc. Is there a way i can mock SqlParameterCollection? Is there any other approach to unit test DAL? I am using Moq.
Code goes like this:
in DAL:
protected virtual IDbConnection GetConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
protected virtual IDbCommand GetCommand(IDbConnection cn)
{
return cn.CreateCommand();
}
protected virtual IDbTransaction GetTransaction(IDbConnection cn)
{
return cn.BeginTransaction(IsolationLevel.Serializable);
}
Public Bool InsertInDatabase(DataTable dt)
{
using (IDbConnection cn = GetConnection(cnstr))
{
cn.Open();
using (IDbTransaction tran = GetTransaction(cn))
{
IDbCommand cmd = GetCommand(cn);
cmd.Transaction = tran;
cmd.Connection = cn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_InsertInDatabase";
SqlParameterCollection cmdParams = cmd.Parameters as SqlParameterCollection;
cmdParams.AddWithValue("#param1", dt);
cmd.ExecuteNonQuery();
}
}
}
In Unit test project:
protected override IDbConnection GetConnection(string connectionString)
{
return Mock.Of<IDbConnection>();
}
protected override IDbCommand GetCommand(IDbConnection cn)
{
return Mock.Of<IDbCommand>();
}
protected override IDbTransaction GetTransaction(IDbConnection cn)
{
return Mock.Of<IDbTransaction>();
}
public void TestInsertInDatabase()
{
base.InsertInDatabase(new DataTable());
}
--Solution--
Created an extension method to add parameter with value. Thank you Marc Gravell for pointing me to that direction.
public static IDbDataParameter AddParameterWithValue(this IDbCommand cmd, string paramName, object paramValue)
{
var dbParam = cmd.CreateParameter();
if (dbParam != null)
{
dbParam.ParameterName = paramName;
dbParam.Value = paramValue;
}
return dbParam;
}
Personally, I approach this problem by writing an AddParameterWithValue extension method to DbCommand (or IDbCommand). It has to be on the command so that you have access to CreateParameter, and then call .Parameters.Add.
This allows easy usage against any ADO.NET stack, including abstractions like logging decorators.
#Asdfg HI I have basically mocked the parameter collection as below
string connectionString = "connectionstring";
var sqlConnection = new SqlConnection(connectionString);
var command = sqlConnection.CreateCommand();
//****************Setup Mock************************//
Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add(typeof(System.Data.SqlClient.SqlClientPermissionAttribute));
var mockDataReader1 = new Mock<IDataReader>();
command.Parameters.Add(new SqlParameter("#po_tint_Result", 1));
//setup read return value
Queue<bool> responseQueue = new Queue<bool>();
responseQueue.Enqueue(true);
responseQueue.Enqueue(false);
mockDataReader1.Setup(a => a.Read()).Returns(() => responseQueue.Dequeue());
var mockDb = new Mock<SqlDatabase>(connectionString);
mockDb.Setup(a => a.GetStoredProcCommand("SPNAME")).Returns(command);
mockDb.Setup(a => a.ExecuteNonQuery(command));
obj1.DbConn = mockDb.Object;
//*************************************************//
Hope this helps
Hi i found the solution.
I had to implement a Moq for the IDataParameterCollection interface and had to send it to the instance of IDbCommand.
With that my IDbCommand.Parameters object became different from null.
public static IDbConnection IDbConnectionMock(int valReturn)
{
var dataParameterCollection = new Mock<IDataParameterCollection>();
var command = new Mock<IDbCommand>();
command.Setup(x => x.Parameters).Returns(dataParameterCollection.Object);
command.Setup(x => x.ExecuteNonQuery()).Returns(valReturn);
var connection = DbConnectionMock_Success(command.Object);
return connection;
}

Categories

Resources