Repository Pattern & UnitOfWork Implementation For Dommel.
Dommel.Repositories is a library that makes the implementation of Repository Pattern and UnitOfWork a lot easier. The Implementation sample taken from Tim Schreiber example.
Nuget
Directly download from Nuget
Package Manager Console
PM > Install-Package Dommel.Repositories
POCO's:
[Table(nameof(Category))]
public class Category
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
[Table(nameof(Product))]
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public int? CategoryId { get; set; }
public Category Category { get; set; }
}
-
Async Repository (Asynchronous CRUD operations)
- Async UnitOfWork -
Sync Repository (Synchronous CRUD Operations)
- Sync UnitOfWork
It's all up to you to inherit from which one, Here we inherit the repository for entities from synchronous repository base.
public class CategoryRepository : SyncRepository<Category>
{
public CategoryRepository(IDbConnection connection) : base(connection)
{
}
// Custom other operations other than those provided by the library.
}
public class ProductRepository : SyncRepository<Product>
{
public ProductRepository(IDbConnection connection) : base(connection)
{
}
// Custom other operations other than those provided by the library.
}
We also inherit our context from synchronous unitofwork:
public class AppDbContext : SyncUnitOfWork
{
private ISyncRepository<Category> _categories;
private ISyncRepository<Product> _products;
public AppDbContext(IConnection connection, IConnectionHelper connectionHelper)
: base(connection, connectionHelper)
{
}
public ISyncRepository<Product> Products =>
_products ?? new ProductRepository(Connection);
public ISyncRepository<Category> Categories =>
_categories ?? new CategoryRepository(Connection);
protected override void ResetRepositories()
{
_products = null;
_categories = null;
}
}
Note:
Both AsyncUnitOfWork and SyncUnitOfWork contain constructor parameters -[x] IConnection (Connection type such as SQLiteConnection, SqlConnection, MySqlConnection, ...) -[x] IConnectionHelper (Connection string)
You need to implement these two interfaces as well, for example (sqlite):
public class DbConnection : IConnection
{
public IDbConnection Connection(string connectionString)
{
return new SQLiteConnection(connectionString);
}
}
public class ConnectionHelper : IConnectionHelper
{
public string ConnectionString => @"Data Source=.\Database.db;Version=3;";
}
internal static class Program
{
static void Main(string[] args)
{
// Insert Category
using var context = new AppDbContext(new DbConnection(), new ConnectionHelper());
var result = (long) context.Categories.Insert(category) > 0;
result &= context.SaveChanges();
if (result)
Console.WriteLine($"{category.Name} Successfully Inserted.");
// Read Category By Id with it's products.
using var context = new AppDbContext(new DbConnection(), new ConnectionHelper());
var category = context.Categories.GetById<Product>(1);
Console.WriteLine(
$" Category Id : {category.Id} \n Category Name : {category.Name} \n Product : {category.Products.FirstOrDefault()?.Name}");
// Read Products with their categories.
using var context = new AppDbContext(new DbConnection(), new ConnectionHelper());
// Get Products with their categories.
var products = context.Products.GetAll<Category>();
foreach (var product in products)
{
Console.WriteLine(
$" Product Id : {product.Id} \n Product Name : {product.Name} \n CategoryName : {product.Category?.Name}");
}
}
{
See the full Demo.
T GetById(int id);
T GetById<T2>(int id);
T GetById<T2, T3>(int id);
T GetById<T2, T3, T4>(int id);
T GetById<T2, T3, T4, T5>(int id);
T GetById<T2, T3, T4, T5, T6>(int id);
IEnumerable<T> GetAll();
IEnumerable<T> GetAll<T2>();
IEnumerable<T> GetAll<T2, T3>();
IEnumerable<T> GetAll<T2, T3, T4>();
IEnumerable<T> GetAll<T2, T3, T4, T5>();
IEnumerable<T> GetAll<T2, T3, T4, T5, T6>();
object Insert(T entity);
bool Delete(T entity);
int DeleteMultiple(Expression<Func<T, bool>> predicate);
int DeleteAll();
bool Update(T entity);
IEnumerable<T> Select(Expression<Func<T, bool>> predicate);
IEnumerable<T> SelectPaged(Expression<Func<T, bool>> predicate, int pageNumber, int pageSize);
T FirstOrDefault(Expression<Func<T, bool>> predicate);
You can simply create an interface for the repository inhert from IAsyncRepository or ISyncRepository
public interface ICategoryRepository : ISyncRepository<Category>
{
}
public class CategoryRepository : SyncRepository<Category>, ICategoryRepository
{
public CategoryRepository(IDbConnection connection) : base(connection)
{
}
}
Then simply registering it like:
Container.RegisterType<ICategoryRepository, CategoryRepository>();