Link Search Menu Expand Document

Generic Repository


This page has the consolidated code of the GenericRepository reference implementation.

Interface

public interface IRepositoryBase<TDbConnection>
    where TDbConnection : DbConnection
{
    /*** Helper ***/

    TDbConnection GetConnection();

    /*** Non-Async ***/

    IEnumerable<TEntity> GetAll<TEntity>(string cacheKey = null);

    TEntity Get<TEntity>(object id);

    int Delete<TEntity>(object id);

    object Merge<TEntity>(TEntity entity);

    object Save<TEntity>(TEntity entity);

    int Update<TEntity>(TEntity entity);

    /*** Async ***/

    Task<IEnumerable<TEntity>> GetAllAsync<TEntity>(string cacheKey = null);

    Task<TEntity> GetAsync<TEntity>(object id);

    Task<int> DeleteAsync<TEntity>(object id);

    Task<objec> MergeAsync<TEntity>(TEntity entity);
    
    Task<object> SaveAsync<TEntity>(TEntity entity);

    Task<int> UpdateAsync<TEntity>(TEntity entity);
}

Repository (Base)

public class RepositoryBase<TDbConnection> : IRepositoryBase<TDbConnection>
    where TDbConnection : DbConnection
{
    private IOptions<AppSettings> _settings;

    public RepositoryBase(IOptions<AppSetting> settings,
        ICache cache,
        ITrace trace)
    {
        _settings = settings;
        Cache = cache;
        Trace = trace;
    }

    /*** Properties ***/

    public ITrace Trace { get; }

    public ICache Cache { get; }

    /*** Methods ***/
    
    public TDbConnection CreateConnection()
    {
        var connection = Activator.CreateInstance<TDbConnection>();
        connection.ConnectionString = _settings.Value.ConnectionString;
        return connection;
    }

    /*** Non-Async ***/

    // Get (Many)
        
    public IEnumerable<TEntity> GetAll<TEntity>(string cacheKey = null)
    {
        using (var connection = CreateConnection())
        {
            return connection.QueryAll<TEntity>(cacheKey: cacheKey,
                commandTimeout: _settings.CommandTimeout,
                cache: Cache,
                cacheItemExpiration: _settings.CacheItemExpiration,
                trace: Trace);
        }
    }

    // Get

    public TEntity Get<TEntity>(int id)
    {
        using (var connection = CreateConnection())
        {
            return connection.Query<TEntity>(id,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Delete

    public int Delete<TEntity>(int id)
    {
        using (var connection = CreateConnection())
        {
            return connection.Delete<TEntity>(id,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Merge

    public int Merge<TEntity>(TEntity entity,
        IDbTransaction transaction = null)
    {
        using (var connection = CreateConnection())
        {
            return connection.Merge<TEntity, int>(entity,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Save

    public int Save<TEntity>(TEntity entity,
        IDbTransaction transaction = null)
    {
        using (var connection = CreateConnection())
        {
            return connection.Save<TEntity, int>(entity,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Update

    public int Update<TEntity>(TEntity entity,
        IDbTransaction transaction = null)
    {
        using (var connection = CreateConnection())
        {
            return Update<TEntity>(entity,
                transaction: transaction,
                trace: Trace);
        }
    }

    /*** Async ***/

    // Get (Many)

    public async Task<IEnumerable<TEntity>> GetAllAsync<TEntity>(string cacheKey = null)
    {
        using (var connection = CreateConnection())
        {
            return await connection.QueryAllAsync<TEntity>(cacheKey: cacheKey,
                commandTimeout: _settings.CommandTimeout,
                cache: Cache,
                cacheItemExpiration: _settings.CacheItemExpiration,
                trace: Trace);
        }
    }

    // Get

    public async Task<TEntity> GetAsync<TEntity>(int id)
    {
        using (var connection = CreateConnection())
        {
            return await connection.QueryAsync<TEntity>(id,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Delete

    public async Task<int> DeleteAsync<TEntity>(int id)
    {
        using (var connection = CreateConnection())
        {
            return await connection.DeleteAsync<TEntity>(id,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Merge

    public async Task<objec> MergeAsync<TEntity>(TEntity entity)
    {
        using (var connection = CreateConnection())
        {
            return await connection.MergeAsync<TEntity>(entity,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Save

    public async Task<object> SaveAsync<TEntity>(TEntity entity)
    {
        using (var connection = CreateConnection())
        {
            return await connection.SaveAsync<TEntity>(entity,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }

    // Update

    public async Task<int> UpdateAsync<TEntity>(TEntity entity)
    {
        using (var connection = CreateConnection())
        {
            return await connection.UpdateAsync<TEntity>(entity,
                commandTimeout: _settings.CommandTimeout,
                trace: Trace);
        }
    }
}

Derived Repository Interface

public interface INorthwindRepository
{
    /*** Non-Async ***/

    // Get

    Customer GetCustomer(int id);

    Order GetOrder(int id);

    Product GetProduct(int id);

    // Delete

    ...

    // Merge

    ...

    // Save

    int SaveCustomer(Customer customer);

    int SaveOrder(Order order);

    int SaveProduct(Product product);

    void SaveCustomerOrder(int customerId,
        int productId);
        
    // Update

    ...

    /*** Async **/

    ...
}

Derived Repository

public class NorthwindRepository : RepositoryBase<SqlConnection>, INorthwindRepository
{
    public NorthwindRepository(IOptions<AppSetting> settings)
        : base(settings)
    { }

    /*** Non-Async ***/

    // Get
    
    public Customer GetCustomer(int id)
    {
        return base.Get<Customer>(customer);
    }

    public Order GetOrder(int id)
    {
        return base.Get<Order>(order);
    }

    public Product GetProduct(int id)
    {
        return base.Get<Product>(product);
    }

    // Delete

    ...

    // Merge

    ...

    // Save

    public int SaveCustomer(Customer customer)
    {
        return base.Save<Customer, int>(customer);
    }

    public int SaveOrder(Order order)
    {
        return base.Save<Order, int>(order);
    }

    public int SaveProduct(Product product)
    {
        return base.Save<Product, int>(product);
    }

    // Update

    ...

    // Unit of Work
    
    public void SaveCustomerOrder(int customerId,
        int productId)
    {
        using (var connection = CreateConnection())
        {
            using (var transaction = connection.BeginTransaction())
            {
                // Get the product
                var product = connection.Query<Product>(productId, transaction: transaction).FirstOrDefault();

                // Save the order
                var order = new Order
                {
                    CustomerId = customerId,
                    ProductId = productId,
                    CurrentPrice = product.Price,
                    OrderDateUtc = DateTime.UtcNow
                };
                order.CustomerId = customerId;
                var orderId = connection.Save<Order>(order, transaction: transaction);

                // Commit the transaction
                transaction.Commit();
            }
        }
    }

    /*** Async ***/
    
    ...
}

Settings

public class AppSetting
{
    public string ConnectionString { get; set; }
    public int CommandTimeout { get; set; }
    public int CacheItemExpiration { get; set; }
}

Dependency Injection

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    // Registration
    services.AddSingleton<INorthwindRepository, NorthwindRepository>();
}

Cache

// Custom Class
public static class MyCustomCache : MemoryCache
{
    ...
}

// Factory
public static class CacheFactory
{
    private static object _syncLock = new object();
    private static ICache _cache = null;
    
    public static ICache CreateCacher()
    {
        if (_cache == null)
        {
            lock (_syncLock)
            {
                if (_cache == null)
                {
                    _cache = new MyCustomCache();
                }
            }
        }
        return _cache;
    }
}

// Dependency Injection
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    // Registration
    services.AddSingleton<ICache, MyCustomCache>();
}

Trace

// Custom Class
public static class MyCustomTrace : ITrace
{
    /* Implement all the methods here */
}

// Factory
public static class TraceFactory
{
    private static object _syncLock = new object();
    private static ITrace _trace = null;
    
    public static ITrace CreateTracer()
    {
        if (_trace == null)
        {
            lock (_syncLock)
            {
                if (_trace == null)
                {
                    _trace = new MyCustomTrace();
                }
            }
        }
        return _trace;
    }
}

// Dependency Injection
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    // Registration
    services.AddSingleton<ITrace, MyCustomTrace>();
}