How to separate the Data Access Layer into smaller classes - c#

I have a design problem with a 3 Tier application. Usually my database layer is only 1 class like this one:
public class DA
{
string _connString = "";
public DA()
{
_connString = ConfigurationManager.ConnectionStrings["MyConnString"].ToString();
}
public DA(string connString)
{
_connString = connString;
}
private SqlConnection GetConnection()
{
...
}
public Employee GetEmployee(int idEmployee)
{
...
}
public Whatever GetWhatever(int idWhatever)
{
...
}
...
But now I have a pretty big project and I would like to separate the DA class into smaller classes like DA_Employee, DA_Whatever, etc.
I would like to instantiate only DA one time and access the other classes like that:
DA db = new DA(connString);
db.Employee.GetEmployee(12);
db.Whatever.GetWhatever(89);
db.Whatever.UpdateWhatever(89, "newname");
I would prefer NOT having something like this:
DA db = new DA(connString);
DA_Employee dbEmployee = new DA_Employee(connString);
DA_Whatever dbWhataver = new DA_Whatever(connString);
I think I can instantiate all my classes in my main constructor and have some properties to access them?
How can I give access to all classes to GetConnection()?
Any help and reference appreciated.
Thanks!

Yes, you make the classes a property of DA.
public interface IRepository<T>
{
T GetById(int id);
}
public class EmployeeRepository : IRepository<Employee>
{
private SqlConnection sqlConn;
public EmployeeRepository(SqlConnection sqlconn)
{
this.sqlConn = sqlConn;
}
public Employee GetById(int id)
{
return new Employee();
}
}
Pass the SqlConnection as a constructor dependency.
public class DA : IDisposable
{
private SqlConnection sqlConn;
private IRepository<Employee> employeeRepo;
private IReposiotry<Whatever> whateverRepo;
public DA(string connectionString)
{
this.sqlConnection = GetSqlConnection(connectionString);
this.employeeRepo = new EmployeeRepository(this.sqlConnection);
this.whateverRepo = new WhateverRepository(this.sqlConnection);
}
public IRepository<Employee> Employee { get { return employeeRepo; } }
public IRepository<Whatever> Whatever { get { return whateverRepo; } }
}
And its usage
using (var db = new DA("connectionString"))
{
db.Employee.GetById(1);
db.Whatever.GetById(10);
}

Related

How to mock method which is called multiple times c#

I have a common method which is being called multiple times(around 30-35 references in the project). This method is basically fetching data from DB into data table.
Following is the testable code:
public class MyApp
{
private readonly IDataProvider _dbProvider;
public MyApp(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
}
public void Process()
{
string query = "something";
Helper h = new Helper(_dbProvider);
// This method will be called in the Process method several times
var data = h.GetData(query);
}
}
public interface IDataProvider
{
IDbConnection CreateConnection(string connectionString);
DataTable FillDatatableFromAdapter(IDbCommand command);
}
public class DataProvider : IDataProvider
{
public IDbConnection CreateConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
public DataTable FillDatatableFromAdapter(IDbCommand command)
{
DataSet dataSet = new DataSet();
SqlCommand sqlCommand = command as SqlCommand;
using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand))
{
sqlDataAdapter.Fill(dataSet);
}
if (dataSet.Tables.Count == 0)
return null;
return dataSet.Tables[0];
}
}
public class Helper
{
private readonly IDataProvider _dbProvider;
public Helper(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
}
public DataTable GetData(string query)
{
DataTable table = new DataTable();
using (IDbConnection connection =
_databaseProvider.CreateConnection(_connectionString))
{
connection.Open();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = query;
command.Connection = connection;
table = _dbProvider.FillDatatableFromAdapter(command);
}
}
return table;
}
}
I have mocked DB classes to not hit DB from unit tests.
Following is the test case code:
[TestMethod]
public void TestMyApp()
{
Mock<IDbCommand> mockDbCommand = new Mock<IDbCommand>();
Mock<IDbConnection> mockDbConnection = new Mock<IDbConnection>();
Mock<IDataProvider> mockDatabaseProvider = new Mock<IDataProvider();
mockDbConnection.Setup(m => m.CreateCommand()).Returns(mockDbCommand.Object);
mockDatabaseProvider.Setup(m => m.CreateConnection(It.IsAny<string>())).Returns(mockDbConnection.Object);
DataTable table = new DataTable();
mockDatabaseProvider.SetupSequence(mock => mock.FillDatatableFromAdapter(It.IsAny<IDbCommand>()))
.Returns(dataTable);
MyApp app = new MyApp(mockDatabaseProvider.Object);
app.Process();
// And then after that I am testing some data.
}
I will be calling GetData() method several times and therefore FillDatatableFromAdapter will also be called several times. As in the above test case I have mocked FillDatatableFromAdapter method and I am returning some fake data table for further testing.
I am aware of SetupSequence method in Moq which I can use to return multiple data tables from the mocked method everytime that method is called.
I want a suggestion is that approach correct because then I will have to create that many number of Data tables which will be return from the mocked method using SetupSequence? Or is there some other better approach?
Any help??
You need to define what you want to test.
A small refactoring will help you better test your code
public class MyApp
{
private readonly IDataProvider _dbProvider;
private readonly IHelper _h;
public MyApp(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
_h = new Helper(_dbProvider);
}
public void Process()
{
string query = "something";
// This method will be called in the Process method several times
var data = _h.GetData(query);
}
}
public interface IDataProvider
{
IDbConnection CreateConnection(string connectionString);
DataTable FillDatatableFromAdapter(IDbCommand command);
}
public class DataProvider : IDataProvider
{
public IDbConnection CreateConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
public DataTable FillDatatableFromAdapter(IDbCommand command)
{
DataSet dataSet = new DataSet();
SqlCommand sqlCommand = command as SqlCommand;
using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand))
{
sqlDataAdapter.Fill(dataSet);
}
if (dataSet.Tables.Count == 0)
return null;
return dataSet.Tables[0];
}
}
public interface IHelper
{
public DataTable GetData(string query);
}
public class Helper
{
private readonly IDataProvider _dbProvider;
public Helper(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
}
public DataTable GetData(string query)
{
DataTable table = new DataTable();
using (IDbConnection connection =
_databaseProvider.CreateConnection(_connectionString))
{
connection.Open();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = query;
command.Connection = connection;
table = _dbProvider.FillDatatableFromAdapter(command);
}
}
return table;
}
}
Now you can have 4 isolated tests
[TestMethod]
public void TestProccessFunctionCallHelperGetData()
{
Mock<IHelper> mockHelper = new Mock<IHelper>();
Mock<IDataProvider> mockDatabaseProvider = new Mock<IDataProvider();
mockHelper.Setup(m => m.getData(It.IsAny<string>())).Returns(new DataTable());
MyApp app = new MyApp(mockDatabaseProvider.Object, mockHelper.Setup);
app.Process();
Assert.AreEquals(mockHelper.numTimesCalled, 1);
}
[TestMethod]
public void TestHelperGetData()
{
var query = ""; //TODO: write dummy query
var dataTableToReturn = new DataTable(); //TODO: add some data
Mock<IDataProvider> mockDatabaseProvider = new Mock<IDataProvider();
mockDatabaseProvider.Setup(m => m.CreateConnection(It.IsAny<string>())).Returns(new SqlConnection("dummy connection string"));
mockDatabaseProvider.Setup(m => m.FillDatatableFromAdapter(It.IsAny<IDbCommand>())).Returns(dataTableToReturn );
IHelper h = new Helper(mockDatabaseProvider.Object);
var actualDataTable = h.getData(query);
Assert.AreEqual(dataTableToReturn, actualDataTable );
}
[TestMethod]
public void TestDataProviderFillDataTableFromAdapter()
{
//This test seems to me more like integration test because you need to mock a db or use a real db
}
[TestMethod]
public void TestYourData()
{
// Create a dataTable with data so you can continue with your testing
}

How can I improve this working sqldependency implementation?

I'm a beginner with C# MVC (about 6 months of self-learning), currently working on my first project, and I recently came across the problem of an SQL dependency duplicating when the user refreshes a page.
Through looking at various posts and articles across sites, I have cobbled together a working implementation, but I'm still getting my head around some of the elements of it, especially the singleton design pattern and the various class and property modifiers.
I would like to know, are there any gaping holes in my code, or any other considerations I should be making as I plan to set up a few more dependencies?
To give a bit of background to the project scale, it will be used by up to 500 users at a time, and the data affecting the dependency will change up to around once a second during busy periods.
Many thanks in advance. :)
Here is my dependency class:
public sealed class UMCSingleton
{
private static UMCSingleton instance;
private static string connString = ConfigurationManager.ConnectionStrings["ServerConnection"].ConnectionString;
private static SqlConnection conn = new SqlConnection(connString);
private SqlDependency dependency;
private static volatile object padlock = new object();
private UMCSingleton() {}
public static UMCSingleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new UMCSingleton();
}
}
}
return instance;
}
}
public static SqlConnection getUMCConnection()
{
try
{
if(conn == null)
{
conn = new SqlConnection(connString);
conn.Open();
return conn;
}
if(conn.State == ConnectionState.Closed)
{
conn.ConnectionString = connString;
conn.Open();
}
}
catch (SqlException e) {}
finally {}
return conn;
}
public void RegisterUnmanagdCallDependency()
{
using (getUMCConnection())
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT [CallRef], [CallLoggedByUserId] FROM [dbo].[UnplannedCustomers] Where [ServiceFlowId] = 1";
cmd.Notification = null;
if (dependency == null || dependency.HasChanges == true)
{
dependency = new SqlDependency(cmd);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
}
using (SqlDataReader reader = cmd.ExecuteReader()) {}
}
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e) //this will be called when any changes occur in db table.
{
if (e.Type == SqlNotificationType.Change)
{
SqlDependency dependency = (SqlDependency)sender;
if (dependency.HasChanges == true)
{
dependency.OnChange -= dependency_OnChange;
}
UnmanagedCallHub.ShowCalls();
RegisterUnmanagdCallDependency();
}
}
}
Here is my hub class:
public class UnmanagedCallHubData
{
public string CallRef { get; set; }
public string RaisedBy { get; set; }
}
public class UnmanagedCallHub : Hub
{
private ApplicationDbContext _context;
public UnmanagedCallHub()
{
_context = new ApplicationDbContext();
}
public static void ShowCalls()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<UnmanagedCallHub>();
context.Clients.All.UpdateCalls();
}
}
And finally my api controller:
public class UnmanagedCallController : ApiController
{
private ApplicationDbContext _context;
private UserProfile _uPro;
//CONSTRUCTOR SETS DB CONTEXT
public UnmanagedCallController()
{
_context = new ApplicationDbContext();
ApplicationUser user = HttpContext.Current.GetOwinContext()
.GetUserManager<ApplicationUserManager>().FindById(HttpContext.Current.User.Identity.GetUserId());
_uPro = _context.UserProfiles.SingleOrDefault(x => x.UserId == user.Id);
}
[HttpGet]
[Authorize]
public List<UnmanagedCallHubData> GetUnmanagedCalls()
{
List<UnmanagedCallHubData> calls = _context.UnplannedCustomers
.Where(x => x.ServiceFlowId == 1)
.Where(x => x.CurrentManagerUserId == null)
.Select(x => new UnmanagedCallHubData
{
CallRef = x.CallRef,
RaisedBy = x.CallLoggedByUserId
}).ToList();
UMCSingleton.Instance.RegisterUnmanagdCallDependency();
return calls;
}
}

Unable to change label text when Invoking Method through Reflection in c#

First Look at my code
namespace HealthClub
{
public partial class frmTrainerMaster : Form
{
DataTable dt = new DataTable();
frmHome Home = new frmHome();
public frmTrainerMaster()
{
InitializeComponent();
}
}
private void frmTrainerMaster_Load(object sender, EventArgs e)
{
FillValues("UserNameText");
}
public void FillValues(string UserName)
{
DataTable DT;
SqlCommand cmd = new SqlCommand();
try
{
cmd.Connection = Connections.Connection[UserName];
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "TrainerMaster_pro";
cmd.Parameters.AddWithValue("Option", "FillValues".Trim());
if (Connections.Connection[UserName].State == ConnectionState.Closed)
Connections.Connection[UserName].Open();
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DT = new DataTable();
adp.Fill(DT);
lblId___.Text = DT.Rows[0][0].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
cmd.Parameters.Clear();
cmd.Dispose();
Connections.Connection[UserName].Close();
}
}
}
Now I am calling FillValues() from another class like this
class AnotherClass
{
public void TestMethod(string FormName)
{
Type tp = Type.GetType("HealthClub." + FormName);
object myobj = Activator.CreateInstance(tp);
MethodInfo method = myobj.GetType().GetMethod("FillValues");
object[] parametersArray = new object[] { UserName };
method.Invoke(myobj, parametersArray);
}
}
If you look at the FillValues(), I am assigning the database value to a label. When I am calling it in my first class in page load it's working fine.
But when I am Invoking the medthod from second class, Method invokes but database value does not assign to the label.
What extra effort I need to do ?
There is a class and there is an instance. This is very basic concept you need to understand (not just in C#, but in any objective-oriented language).
// class example
class FrmTrainerMaster { public int SomeProperty { get; set;} }
When you create new instance:
// creates one window
var frmTrainerMasterInstanceOne = new FrmTrainerMaster();
frmTrainerMasterInstanceOne.SomeProperty = 1;
// creates second window
var frmTrainerMasterInstanceTwo = new FrmTrainerMaster();
frmTrainerMasterInstanceTwo.SomeProperty = 2;
Instances are SEPARATE - so at this point querying
// will return 1
Console.Out.WriteLine(frmTrainerMasterInstanceOne.SomeProperty);
// will return 2
Console.Out.WriteLine(frmTrainerMasterInstanceTwo.SomeProperty);
With reflection var myobj = Type.GetType("HealthClub.FrmTrainerMaster"); is equal to var myobj = new FrmTrainerMaster(); so by doing anything with myobj, you still can't affect frmTrainerMasterInstanceOne or frmTrainerMasterInstanceTwo.
What do you need is actually method how to pass reference to instance (of FrmTrainerMaster class) to place where you need it (lets call it AnotherForm), there is no magic list of all instances for given class unless you explicitly build it.
public partial class FrmTrainerMaster : Form
{
public void FillValues(string userName) { ... }
}
One way is via constructor injection (generally proffered - since at time when object (AnotherForm) is constructed you have it in valid state (i.e. with all dependencies initialized).
public class AnotherForm : Form {
private readonly FrmTrainMaster _frmTrainMaster;
public AnotherForm(FrmTrainMaster frmTrainMaster) {
if (frmTrainMaster == null) {
throw new ArgumentNullException(nameof(frmTrainMaster));
}
_frmTrainMaster = frmTrainMaster;
}
}
Or via setter injection:
public class AnotherForm : Form {
private FrmTrainMaster _frmTrainMaster;
public FrmTrainMaster MasterForm { set { _frmTrainMaster = value; } }
}
Either way the reflection is not necessary at all. At any place in your AnotherForm you can just call
class AnotherForm : Form {
...
public void FooMethodThatCallFillValues() {
_frmTrainMaster.FillValues("...");
}
}

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.

C# unitesting method with MySql query

I've made an attempt to unit test a methods in the database layer of my app. In my test I was planning to write mocks to avoid having a live connection to MySQL.
I'll write down a simplified version of my code to illustrate. Let's start with the unit test:
[TestMethod()]
public void TestMethod1()
{
DataBaseInterface database = new DataBaseInterface(); // this is the class which has the method I want to unit test
DataSet ds = new DataSet();
ds.Tables.Add(new DataTable("signals"));
ds.Tables[0].Columns.Add(new DataColumn("ID"));
ds.Tables[0].Columns.Add(new DataColumn("Content"));
DataRow row = ds.Tables[0].NewRow();
row["ID"] = "1";
row["Content"] = "Foo";
ds.Tables[0].Rows.Add(row);
MockDataBaseConnection db = new MockDataBaseConnection();
string result = database.GetContent(1); // this is the method I want to unit test
}
The method I want to unit test looks something like this:
public class DatabaseInterface
{
private MySqlConnectionAdapter _sqlConn;
public string GetContent(int i)
{
MySqlCommand command = _sqlConn.CreateCommand();
command.CommandText = String.Format("");
_sqlConn.Open();
MySqlDataReader reader = command.ExecuteReader();
/// more code here
}
To prevent using an actual database connection in my unitest I wrote a few mockups and here lies the problem.
The mockups looks like this:
public class MySqlConnectionAdapter
{
public MySqlConnection _sqlConn;
public MySqlConnectionAdapter()
{
}
public MySqlConnectionAdapter(string con)
{
_sqlConn = new MySqlConnection(con);
}
public event MySqlInfoMessageEventHandler InfoMessage
{
add
{
_sqlConn.InfoMessage += value;
}
remove
{
_sqlConn.InfoMessage -= value;
}
}
public virtual event StateChangeEventHandler StateChange
{
add
{
_sqlConn.StateChange += value;
}
remove
{
_sqlConn.StateChange -= value;
}
}
public virtual void Open()
{
_sqlConn.Open();
}
public void Close()
{
_sqlConn.Close();
}
public string ServerVersion
{
get
{
return _sqlConn.ServerVersion;
}
}
protected DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
return _sqlConn.BeginTransaction(isolationLevel);
}
public void ChangeDatabase(string databaseName)
{
_sqlConn.ChangeDatabase(databaseName);
}
public string ConnectionString
{
get
{
return _sqlConn.ConnectionString;
}
set
{
_sqlConn.ConnectionString = value;
}
}
public virtual MySqlCommand CreateCommand()
{
return _sqlConn.CreateCommand();
}
public string DataSource
{
get
{
return _sqlConn.DataSource;
}
}
public string Database
{
get
{
return _sqlConn.Database;
}
}
public ConnectionState State
{
get
{
return _sqlConn.State;
}
}
}
public class MockDataBaseConnection : MySqlConnectionAdapter
{
public DataSet ds;
public new MockMySqlCommand CreateCommand()
{
return new MockMySqlCommand(ds);
}
}
public class MockMySqlCommand
{
private DataSet _ds;
public MockMySqlReader ExcecuteReader()
{
return new MockMySqlReader(_ds);
}
public MockMySqlCommand(DataSet ds)
{
_ds = ds;
}
}
public class MockMySqlReader
{
public DataSet _ds;
private int currRow = 0;
public MockMySqlReader(DataSet ds)
{
_ds = ds;
}
public bool Read()
{
if (currRow < _ds.Tables[0].Rows.Count)
{
currRow++;
return true;
}
else return false;
}
public object GetValue(int i)
{
return _ds.Tables[0].Rows[currRow][i];
}
}
When the line _sqlConn.CreateCommand() is executed it throws and exeption. Why is that?
The _sqlConn fiels in my unit test method is a MockDataBaseConnection object and I want it to return a MockMySqlCommand object.
The sealed classed of the MySQL dll is giving me a headache. Can anyone explain how I can fix my code or show a simple example of how to unit test a method
which queries a database without actually querying the database.
Like suggested by vulkanino, I think it would be a lot easier to setup a local database instance, and run the tests directly on it.
I've been in the same situation, and developed this project that simply sets up a local running MySql test server instance, without you having to care about server administration: https://github.com/stumpdk/MySql.Server

Categories

Resources