- first of all we have to create interface
Dapper Npgsql
public interface IRepository<T> where T : class
{
	Task AddAsync(T item);
	Task RemoveAsync(T item);
	Task UpdateAsync(T item);
	Task<T> FindAsync(long id);
	Task<IEnumerable<T>> FindAsync(Expression<Func<T, object>> filter, object value);
	Task<IEnumerable<T>> FindAllAsync();
}
- create few entities
public class Operation 
{
		
	public long Id { get;  set; }
	
	public DateTime CreatedAt { get;  set; }
	public JObject Attachment { get; set; }
	public int OperationTypeId { get;  set; }
	public OperationType OperationType { get;  set; }
}
public class OperationType
{
	
	public int Id { get; set; }	
	public string Description { get; set; }
	
}
	
- implement base repository
DapperExtensions
internal class BaseRepository<T>: IRepository<T>  where T : class
{
	protected string _connectionString;        
						
	public BaseRepository(string connectionString)
	{
		_connectionString = connectionString;            
	}
	public async Task AddAsync(T item)
	{
		using (IDbConnection cn = await _getConnectionAsync())
		{                                
			await cn.InsertAsync<T>(item);
			cn.Close();
		}
	}
	public async Task<IEnumerable<T>> FindAsync(Expression<Func<T, object>> filter, object value)
	{
		using (var db = await _getConnectionAsync())
		{
			var predicate = Predicates.Field(filter, Operator.Eq, value);
			var result = await db.GetListAsync<T>(predicate);
			db.Close();
			return result;
		}
	}
	public async Task<IEnumerable<T>> FindAllAsync()
	{
		using (var db = await _getConnectionAsync())
		{                
			var result = await db.GetListAsync<T>();
			db.Close();
			return result;
		}
	}
	public async Task<T> FindAsync(long id)
	{
		using (var db = await _getConnectionAsync())
		{
			var result = await db.GetAsync<T>(id);
			db.Close();
			return result;
		}
	}
	public async Task RemoveAsync(T item)
	{
		using (var db = await _getConnectionAsync())
		{
			var result = await db.DeleteAsync<T>(item);
			db.Close();                
		}
	}
	public async Task UpdateAsync(T item)
	{
		using (var db = await _getConnectionAsync())
		{
			var result = await db.UpdateAsync<T>(item);
			db.Close();
		}
	}
	
	/// <summary>
	/// creates connection to database
	/// </summary>
	/// <returns>opened connection</returns>
	private async Task<IDbConnection> _getConnectionAsync()
	{
		var conn = new NpgsqlConnection(_connectionString);
		await conn.OpenAsync();
		return conn;
	}
}
- create dbcontext which contains all repositories
public class DbContext
{
	
	public DbContext(string connectionString)
	{
		//postgres support
		DapperExtensions.DapperAsyncExtensions.SqlDialect = new PostgreSqlDialect();
		//jobject to db jsonb handler
		SqlMapper.AddTypeHandler(typeof(JObject), JObjectHandler.Instance);
		OperationTypes = new BaseRepository<OperationType>(connectionString);
		Operations = new BaseRepository<Operation>(connectionString);
		TokenStatuses = new BaseRepository<TokenStatus>(connectionString);
		Tokens = new BaseRepository<Token>(connectionString);
	}
	public IRepository<OperationType> OperationTypes { get; private set; }
	public IRepository<Operation> Operations { get; private set; }        
}
- add mappers
public class OperationMapper: ClassMapper<Operation>
{
	public OperationMapper()
	{
		Table("operations");
		Map(x => x.Id).Key(KeyType.Identity);
		Map(x => x.CreatedAt).Column("registration_ts");
		Map(x => x.OperationTypeId).Column("operation_type");
		Map(x => x.OperationType).Ignore();
		//map all other columns
		AutoMap();
	}
}
 public class OperationTypeMapper: ClassMapper<OperationType>
{
	public OperationTypeMapper()
	{
		Table("operation_types");
		Map(x => x.Id).Key(KeyType.Identity);
		//map all other columns
		AutoMap();
	}
}
- add jobject handler
    class JObjectHandler : TypeHandler<JObject> { private JObjectHandler() { } public static JObjectHandler Instance { get; } = new JObjectHandler(); public override JObject Parse(object value) { var json = (string)value; return json == null ? null : JObject.Parse(json); } public override void SetValue(IDbDataParameter parameter, JObject value) { parameter.Value = value?.ToString(Newtonsoft.Json.Formatting.None); ((NpgsqlParameter)parameter).NpgsqlDbType = NpgsqlDbType.Jsonb; } }
- Let’s test. Database should set Id for our entity after AddAsync method run
[TestMethod]
public async Task Add()
{
	var item = new Entities.Operation() { CreatedAt = DateTime.Now, Attachment = JObject.Parse("{ test: 'test'}"), OperationTypeId = 1 };
	await _context.Operations.AddAsync(item);
	Assert.AreNotEqual(0, item.id);	
}
