[開源]Dapper Repository 一種實現方式

  1. 接着上篇[開源]Entity Framework 6 Repository 一種實現方式
  2. 因爲Dapper 自己就是輕量級Orm特性,這裏參考Creating a Data Repository using Dapper dynamic queries in dapper 代碼,來解決實體類與Expression<Func<T, bool>> predicate問題;
  3. 您能夠經過Nuget:Install-Package MasterChief.DotNet.Core.Dapper;
  4. 您能夠經過GitHub:MasterChief 查看具體源碼以及單元測試;
  5. 歡迎Star,歡迎Issues;

插播一條求職

  1. 小弟擁有多年C#開發經驗,從事過路燈,消防平臺物聯網平臺開發,座標上海;
  1. 若是貴司在招聘,煩請大佬考慮下,聯繫郵箱:MeetYan@outlook.com

基於Dapper 的Repository實現

public abstract class DapperDbContextBase : IDbContext
{
    #region Constructors
 
    /// <summary>
    ///     構造函數
    /// </summary>
    /// <param name="connectString">鏈接字符串</param>
    protected DapperDbContextBase(string connectString)
    {
        ConnectString = connectString;
    }
 
    #endregion Constructors
 
    #region Properties
 
    /// <summary>
    ///     獲取 是否開啓事務提交
    /// </summary>
    public IDbTransaction CurrentTransaction { get; private set; }
 
    #endregion Properties
 
    #region Fields
 
    /// <summary>
    ///     當前數據庫鏈接
    /// </summary>
    public IDbConnection CurrentConnection =>
        TransactionEnabled ? CurrentTransaction.Connection : CreateConnection();
 
    /// <summary>
    ///     獲取 是否開啓事務提交
    /// </summary>
    public bool TransactionEnabled => CurrentTransaction != null;
 
    /// <summary>
    ///     鏈接字符串
    /// </summary>
    protected readonly string ConnectString;
 
    #endregion Fields
 
    #region Methods
 
    /// <summary>
    ///     顯式開啓數據上下文事務
    /// </summary>
    /// <param name="isolationLevel">指定鏈接的事務鎖定行爲</param>
    public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
    {
        if (!TransactionEnabled) CurrentTransaction = CreateConnection().BeginTransaction(isolationLevel);
    }
 
    /// <summary>
    ///     提交當前上下文的事務更改
    /// </summary>
    /// <exception cref="DataAccessException">提交數據更新時發生異常:" + msg</exception>
    public void Commit()
    {
        if (TransactionEnabled)
            try
            {
                CurrentTransaction.Commit();
            }
            catch (Exception ex)
            {
                if (ex.InnerException?.InnerException is SqlException sqlEx)
                {
                    var msg = DataBaseHelper.GetSqlExceptionMessage(sqlEx.Number);
                    throw new DataAccessException("提交數據更新時發生異常:" + msg, sqlEx);
                }
 
                throw;
            }
    }
 
    /// <summary>
    ///     建立記錄
    /// </summary>
    /// <param name="entity">須要操做的實體類</param>
    /// <returns>操做是否成功</returns>
    public bool Create<T>(T entity)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entity, "須要新增的數據記錄");
        // insert single data always return 0 but the data is inserted in database successfully
        //https://github.com/StackExchange/Dapper/issues/587
        //List<T> data = new List<T>() { entity };
 
        return CurrentConnection.Insert(new List<T> {entity}, CurrentTransaction) > 0;
 
        #region 測試代碼
 
        //string sql = @"INSERT INTO [dbo].[EFSample]
        //      ([ID]
        //      ,[CreateTime]
        //      ,[ModifyTime]
        //      ,[Available]
        //      ,[UserName])
        //VALUES
        //      (@ID
        //      ,@CreateTime
        //      ,@ModifyTime
        //      ,@Available
        //      ,@UserName)";
 
        //return CurrentConnection.Execute(sql, entity) > 0;
 
        #endregion 測試代碼
    }
 
    /// <summary>
    ///     建立數據庫鏈接IDbConnection
    /// </summary>
    /// <returns></returns>
    public abstract IDbConnection CreateConnection();
 
    /// <summary>
    ///     刪除記錄
    /// </summary>
    /// <returns>操做是否成功</returns>
    /// <param name="entity">須要操做的實體類.</param>
    public bool Delete<T>(T entity)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entity, "須要刪除的數據記錄");
        return CurrentConnection.Delete(entity);
    }
 
    /// <summary>
    ///     執行與釋放或重置非託管資源關聯的應用程序定義的任務。
    /// </summary>
    public void Dispose()
    {
        if (CurrentTransaction != null)
        {
            CurrentTransaction.Dispose();
            CurrentTransaction = null;
        }
 
        CurrentConnection?.Dispose();
    }
 
    /// <summary>
    ///     條件判斷是否存在
    /// </summary>
    /// <returns>是否存在</returns>
    /// <param name="predicate">判斷條件委託</param>
    public bool Exist<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        var tableName = GetTableName<T>();
        var queryResult = DynamicQuery.GetDynamicQuery(tableName, predicate);
 
        var result =
            CurrentConnection.ExecuteScalar(queryResult.Sql, (object) queryResult.Param, CurrentTransaction);
        return result != null;
    }
 
    /// <summary>
    ///     根據id獲取記錄
    /// </summary>
    /// <returns>記錄</returns>
    /// <param name="id">id.</param>
    public T GetByKeyId<T>(object id)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(id, "Id");
        return CurrentConnection.Get<T>(id, CurrentTransaction);
    }
 
    /// <summary>
    ///     條件獲取記錄集合
    /// </summary>
    /// <returns>集合</returns>
    /// <param name="predicate">篩選條件.</param>
    public List<T> GetList<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        var tableName = GetTableName<T>();
        var queryResult = DynamicQuery.GetDynamicQuery(tableName, predicate);
 
        return CurrentConnection.Query<T>(queryResult.Sql, (object) queryResult.Param, CurrentTransaction).ToList();
    }
 
    /// <summary>
    ///     條件獲取記錄第一條或者默認
    /// </summary>
    /// <returns>記錄</returns>
    /// <param name="predicate">篩選條件.</param>
    public T GetFirstOrDefault<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        var tableName = GetTableName<T>();
        var queryResult = DynamicQuery.GetDynamicQuery(tableName, predicate);
 
        return CurrentConnection.QueryFirst<T>(queryResult.Sql, (object) queryResult.Param, CurrentTransaction);
    }
 
    /// <summary>
    ///     條件查詢
    /// </summary>
    /// <returns>IQueryable</returns>
    /// <param name="predicate">篩選條件.</param>
    public IQueryable<T> Query<T>(Expression<Func<T, bool>> predicate = null)
        where T : ModelBase
    {
        throw new NotImplementedException();
    }
 
    /// <summary>
    ///     顯式回滾事務,僅在顯式開啓事務後有用
    /// </summary>
    public void Rollback()
    {
        if (TransactionEnabled) CurrentTransaction.Rollback();
    }
 
    /// <summary>
    ///     執行Sql 腳本查詢
    /// </summary>
    /// <param name="sql">Sql語句</param>
    /// <param name="parameters">參數</param>
    /// <returns>集合</returns>
    public IEnumerable<T> SqlQuery<T>(string sql, IDbDataParameter[] parameters)
    {
        ValidateOperator.Begin()
            .NotNullOrEmpty(sql, "Sql語句");
        var dataParameters = CreateParameter(parameters);
        return CurrentConnection.Query<T>(sql, dataParameters, CurrentTransaction);
    }
 
    /// <summary>
    ///     根據記錄
    /// </summary>
    /// <returns>操做是否成功.</returns>
    /// <param name="entity">實體類記錄.</param>
    public bool Update<T>(T entity)
        where T : ModelBase
    {
        ValidateOperator.Begin().NotNull(entity, "須要更新的數據記錄");
        return CurrentConnection.Update(entity, CurrentTransaction);
    }
 
    private DapperParameter CreateParameter(IDbDataParameter[] parameters)
    {
        if (!(parameters?.Any() ?? false)) return null;
 
        var dataParameters = new DapperParameter();
        foreach (var parameter in parameters) dataParameters.Add(parameter);
        return dataParameters;
    }
 
    private string GetTableName<T>()
        where T : ModelBase
    {
        var tableCfgInfo = AttributeHelper.Get<T, TableAttribute>();
        return tableCfgInfo != null ? tableCfgInfo.Name.Trim() : typeof(T).Name;
    }
 
    #endregion Methods
}

使用方法

public class SampleService : ISampleService
{
    private readonly IDatabaseContextFactory _contextFactory;
 
    public SampleService(IDatabaseContextFactory contextFactory)
    {
        _contextFactory = contextFactory;
    }
 
    /// <summary>
    /// 建立
    /// </summary>
    /// <param name="sample">EFSample</param>
    /// <returns></returns>
    public bool Create(EfSample sample)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.Create(sample);
        }
    }
 
    /// <summary>
    /// 條件查詢
    /// </summary>
    /// <param name="predicate">The predicate.</param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public EfSample GetFirstOrDefault(Expression<Func<EfSample, bool>> predicate = null)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.GetFirstOrDefault(predicate);
        }
    }
 
    /// <summary>
    /// 根據主鍵查詢
    /// </summary>
    /// <param name="id">The identifier.</param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public EfSample GetByKeyId(Guid id)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.GetByKeyId<EfSample>(id);
        }
    }
 
    /// <summary>
    /// 條件查詢集合
    /// </summary>
    /// <param name="predicate">The predicate.</param>
    /// <returns></returns>
    public List<EfSample> GetList(Expression<Func<EfSample, bool>> predicate = null)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.GetList(predicate);
        }
    }
 
    /// <summary>
    /// 添加判斷是否存在
    /// </summary>
    /// <param name="predicate">The predicate.</param>
    /// <returns></returns>
    public bool Exist(Expression<Func<EfSample, bool>> predicate = null)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.Exist(predicate);
        }
    }
 
    /// <summary>
    /// 腳本查詢
    /// </summary>
    /// <param name="sql">The SQL.</param>
    /// <param name="parameter">DbParameter[]</param>
    /// <returns></returns>
    public List<EfSample> SqlQuery(string sql, DbParameter[] parameter)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.SqlQuery<EfSample>(sql, parameter)?.ToList();
        }
    }
 
    /// <summary>
    /// 更新
    /// </summary>
    /// <param name="sample">The sample.</param>
    /// <returns></returns>
    public bool Update(EfSample sample)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.Update(sample);
        }
    }
 
    /// <summary>
    /// 事務
    /// </summary>
    /// <param name="sample">The sample.</param>
    /// <param name="sample2">The sample2.</param>
    /// <returns></returns>
    public bool CreateWithTransaction(EfSample sample, EfSample sample2)
    {
        bool result;
        using (IDbContext context = _contextFactory.Create())
        {
            try
            {
                context.BeginTransaction();//開啓事務
                context.Create(sample);
                context.Create(sample2);
                context.Commit();
                result = true;
            }
            catch (Exception)
            {
                context.Rollback();
                result = false;
            }
        }
 
        return result;
    }
 
    /// <summary>
    /// 刪除
    /// </summary>
    /// <param name="sample"></param>
    /// <returns></returns>
    public bool Delete(EfSample sample)
    {
        using (IDbContext context = _contextFactory.Create())
        {
            return context.Delete(sample);
        }
    }
}

結語

  1. Dapper與Entity Framework都是經過IRepository實現,因此您能夠經過Ioc切換;
  2. 該篇的單元測試寫法與上篇一致;
  3. 小弟不才,大佬輕拍;
相關文章
相關標籤/搜索