当前位置: 首页 > news >正文

.NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现

本篇我将带着大家一起来对Dapper进行下封装并实现基本的增删改查、分页操作的同步异步方法的实现(已实现MSSQL,MySql,PgSQL)。同时我们再实现一下仓储层的代码生成器,这样的话,我们只需要结合业务来实现具体的业务部分的代码就可以了,可以大大减少我们重复而又繁琐的增删改查操作,多留点时间给生活充充电(不会偷懒的程序员不是一位好爸爸/好老公/好男朋友)。如果您觉得我的实现过程有所不妥的话,您可以在评论区留言,或者加入我们的千人.Net Core实战项目交流群637326624交流。另外如果您觉得我的文章对您有所帮助的话希望给个推荐以示支持。项目的源代码我会托管在GayHub上,地址在文章末尾会给出,自认为代码写的很工整,注释也很全,你应该能看懂!

本文已收录至《.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划》

作者:依乐祝

原文地址:https://www.cnblogs.com/yilezhu/p/10146311.html

写在前面

将近一周没有更新,鬼知道我这么长时间在干什么,你可以认为我在憋大招,在想着怎么给大家分享更多更实用的东西。其实这只是我偷懒的借口罢了!下面我们一起来对Dapper进行下封装吧,然后结合Dapper.SimpleCRUD 来实现基本的增删改查、分页操作。这部分功能实现完成后,往下我们也就是基于这些基本操作来实现我们的CMS的业务了,如:权限部分,菜单部分,文章部分的功能。接下来我会对这部分快速的实现,可能会很少更新了,因为这些都是基本的CMS的业务操作,没多少要分享的内容,毕竟每个人的系统业务都不一样,这部分的业务实现也是千差万别的。我后期会把成品直接分享给大家!敬请关注吧!

Dapper的封装

IDbConnection工厂类的封装

这部分我实现了一个IDbConnection的工厂类,以便你可以很方便的根据数据库的类型来创建不同的IDbConnection对象,目前已实现对SqlServer,MySQL,PostgreSQL的实现,具体代码如下,根据传入的参数来进行相关的实现。

       /// <summary>
    /// yilezhu
    /// 2018.12.13
    /// 数据库连接工厂类
    /// </summary>
    public class ConnectionFactory
    {
        /// <summary>
        /// 获取数据库连接
        /// </summary>
        /// <param name="dbtype">数据库类型</param>
        /// <param name="conStr">数据库连接字符串</param>
        /// <returns>数据库连接</returns>
        public static IDbConnection CreateConnection(string dbtype, string strConn)
        {
            if (dbtype.IsNullOrWhiteSpace())
                throw new ArgumentNullException("获取数据库连接居然不传数据库类型,你想上天吗?");
            if (strConn.IsNullOrWhiteSpace())
                throw new ArgumentNullException("获取数据库连接居然不传数据库类型,你想上天吗?");
            var dbType = GetDataBaseType(dbtype);
            return CreateConnection(dbType,strConn);
        }

        /// <summary>
        /// 获取数据库连接
        /// </summary>
        /// <param name="dbType">数据库类型</param>
        /// <param name="conStr">数据库连接字符串</param>
        /// <returns>数据库连接</returns>
        public static IDbConnection CreateConnection(DatabaseType dbType, string strConn)
        {
            IDbConnection connection = null;           
            if (strConn.IsNullOrWhiteSpace())
                throw new ArgumentNullException("获取数据库连接居然不传数据库类型,你想上天吗?");
            
            switch (dbType)
            {
                case DatabaseType.SqlServer:
                    connection = new SqlConnection(strConn);
                    break;
                case DatabaseType.MySQL:
                    connection = new MySqlConnection(strConn);
                    break;
                case DatabaseType.PostgreSQL:
                    connection = new NpgsqlConnection(strConn);
                    break;
                default:
                    throw new ArgumentNullException($"这是我的错,还不支持的{dbType.ToString()}数据库类型");

            }
            if (connection.State == ConnectionState.Closed)
            {
                connection.Open();
            }
            return connection;
        }

        /// <summary>
        /// 转换数据库类型
        /// </summary>
        /// <param name="dbtype">数据库类型字符串</param>
        /// <returns>数据库类型</returns>
        public static DatabaseType GetDataBaseType(string dbtype)
        {
            if (dbtype.IsNullOrWhiteSpace())
                throw new ArgumentNullException("获取数据库连接居然不传数据库类型,你想上天吗?");
            DatabaseType returnValue = DatabaseType.SqlServer;
            foreach (DatabaseType dbType in Enum.GetValues(typeof(DatabaseType)))
            {
                if (dbType.ToString().Equals(dbtype, StringComparison.OrdinalIgnoreCase))
                {
                    returnValue = dbType;
                    break;
                }
            }
            return returnValue;
        }

        
    }

那么,我们怎么来使用这个工厂类呢?如下给出调用的实例。

1545221995138

是不是很简单,感觉瞬间少了很多代码,这段代码摘录自代码生成器里面。有兴趣的自己去查看源码吧!

CRUD及分页泛型方法的实现

  1. nuget安装Dapper.SimpleCRUD ,什么你要问我怎么安装?乖乖的回去看第二篇文章吧!那里会教你如何安装Nuget包?如果那篇文章里面没有,那你就好好想想为啥没有呢?

1545222273003

  1. 新建IBaseRepository泛型接口 定义如下的增删改查方法的同步异步接口,其中还包含分页的实现,具体的代码如下:

    /**
    *┌──────────────────────────────────────────────────────────────┐
    *│ 描    述:                                                    
    *│ 作    者:yilezhu                                             
    *│ 版    本:1.0                                                 
    *│ 创建时间:2018/12/16 20:41:22                             
    *└──────────────────────────────────────────────────────────────┘
    *┌──────────────────────────────────────────────────────────────┐
    *│ 命名空间: Czar.Cms.Core.Repository                                   
    *│ 接口名称: IBaseRepository                                      
    *└──────────────────────────────────────────────────────────────┘
    */
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Czar.Cms.Core.Repository
    {
        public interface IBaseRepository<T,TKey> :  IDisposable where T : class
        {
            #region 同步
            /// <summary>
            /// 通过主键获取实体对象
            /// </summary>
            /// <param name="id">主键ID</param>
            /// <returns></returns>
            T Get(TKey id);
            /// <summary>
            /// 获取所有的数据
            /// </summary>
            /// <returns></returns>
            IEnumerable<T> GetList();
            /// <summary>
            /// 执行具有条件的查询,并将结果映射到强类型列表
            /// </summary>
            /// <param name="whereConditions">条件</param>
            /// <returns></returns>
            IEnumerable<T> GetList(object whereConditions);
            /// <summary>
            /// 带参数的查询满足条件的数据
            /// </summary>
            /// <param name="conditions">条件</param>
            /// <param name="parameters">参数</param>
            /// <returns></returns>
            IEnumerable<T> GetList(string conditions, object parameters = null);
            /// <summary>
            /// 使用where子句执行查询,并将结果映射到具有Paging的强类型List
            /// </summary>
            /// <param name="pageNumber">页码</param>
            /// <param name="rowsPerPage">每页显示数据</param>
            /// <param name="conditions">查询条件</param>
            /// <param name="orderby">排序</param>
            /// <param name="parameters">参数</param>
            /// <returns></returns>
            IEnumerable<T> GetListPaged(int pageNumber, int rowsPerPage, string conditions, string orderby, object parameters = null);
            /// <summary>
            /// 插入一条记录并返回主键值(自增类型返回主键值,否则返回null)
            /// </summary>
            /// <param name="entity"></param>
            /// <returns></returns>
            int? Insert(T entity);
            /// <summary>
            /// 更新一条数据并返回影响的行数
            /// </summary>
            /// <param name="entity"></param>
            /// <returns>影响的行数</returns>
            int Update(T entity);
            /// <summary>
            /// 根据实体主键删除一条数据
            /// </summary>
            /// <param name="id">主键</param>
            /// <returns>影响的行数</returns>
            int Delete(TKey id);
            /// <summary>
            /// 根据实体删除一条数据
            /// </summary>
            /// <param name="entity">实体</param>
            /// <returns>返回影响的行数</returns>
            int Delete(T entity);
            /// <summary>
            /// 条件删除多条记录
            /// </summary>
            /// <param name="whereConditions">条件</param>
            /// <param name="transaction">事务</param>
            /// <param name="commandTimeout">超时时间</param>
            /// <returns>影响的行数</returns>
            int DeleteList(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null);
            /// <summary>
            /// 使用where子句删除多个记录
            /// </summary>
            /// <param name="conditions">wher子句</param>
            /// <param name="parameters">参数</param>
            /// <param name="transaction">事务</param>
            /// <param name="commandTimeout">超时时间</param>
            /// <returns>影响的行数</returns>
            int DeleteList(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null);
            /// <summary>
            /// 满足条件的记录数量
            /// </summary>
            /// <param name="conditions"></param>
            /// <param name="parameters"></param>
            /// <returns></returns>
            int RecordCount(string conditions = "", object parameters = null);
            #endregion
            #region 异步
            /// <summary>
            /// 通过主键获取实体对象
            /// </summary>
            /// <param name="id">主键ID</param>
            /// <returns></returns>
            Task<T> GetAsync(TKey id);
            /// <summary>
            /// 获取所有的数据
            /// </summary>
            /// <returns></returns>
            Task<IEnumerable<T>> GetListAsync();
            /// <summary>
            /// 执行具有条件的查询,并将结果映射到强类型列表
            /// </summary>
            /// <param name="whereConditions">条件</param>
            /// <returns></returns>
            Task<IEnumerable<T>> GetListAsync(object whereConditions);
            /// <summary>
            /// 带参数的查询满足条件的数据
            /// </summary>
            /// <param name="conditions">条件</param>
            /// <param name="parameters">参数</param>
            /// <returns></returns>
            Task<IEnumerable<T>> GetListAsync(string conditions, object parameters = null);
            /// <summary>
            /// 使用where子句执行查询,并将结果映射到具有Paging的强类型List
            /// </summary>
            /// <param name="pageNumber">页码</param>
            /// <param name="rowsPerPage">每页显示数据</param>
            /// <param name="conditions">查询条件</param>
            /// <param name="orderby">排序</param>
            /// <param name="parameters">参数</param>
            /// <returns></returns>
            Task<IEnumerable<T>> GetListPagedAsync(int pageNumber, int rowsPerPage, string conditions, string orderby, object parameters = null);
            /// <summary>
            /// 插入一条记录并返回主键值
            /// </summary>
            /// <param name="entity"></param>
            /// <returns></returns>
            Task<int?> InsertAsync(T entity);
            /// <summary>
            /// 更新一条数据并返回影响的行数
            /// </summary>
            /// <param name="entity"></param>
            /// <returns>影响的行数</returns>
            Task<int> UpdateAsync(T entity);
            /// <summary>
            /// 根据实体主键删除一条数据
            /// </summary>
            /// <param name="id">主键</param>
            /// <returns>影响的行数</returns>
            Task<int> DeleteAsync(TKey id);
            /// <summary>
            /// 根据实体删除一条数据
            /// </summary>
            /// <param name="entity">实体</param>
            /// <returns>返回影响的行数</returns>
            Task<int> DeleteAsync(T entity);
            /// <summary>
            /// 条件删除多条记录
            /// </summary>
            /// <param name="whereConditions">条件</param>
            /// <param name="transaction">事务</param>
            /// <param name="commandTimeout">超时时间</param>
            /// <returns>影响的行数</returns>
            Task<int> DeleteListAsync(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null);
            /// <summary>
            /// 使用where子句删除多个记录
            /// </summary>
            /// <param name="conditions">wher子句</param>
            /// <param name="parameters">参数</param>
            /// <param name="transaction">事务</param>
            /// <param name="commandTimeout">超时时间</param>
            /// <returns>影响的行数</returns>
            Task<int> DeleteListAsync(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null);
            /// <summary>
            /// 满足条件的记录数量
            /// </summary>
            /// <param name="conditions"></param>
            /// <param name="parameters"></param>
            /// <returns></returns>
            Task<int> RecordCountAsync(string conditions = "", object parameters = null);
            #endregion
        }
    }
    
  2. 然后创建一个BaseRepository泛型类来实现上面的接口,其中多了两个成员,DbOpion以及IDbConnection,猜猜看这两个东西有什么用?后面给出答案

    /**
    *┌──────────────────────────────────────────────────────────────┐
    *│ 描    述:仓储类的基类                                                    
    *│ 作    者:yilezhu                                             
    *│ 版    本:1.0                                                 
    *│ 创建时间:2018/12/16 12:03:02                             
    *└──────────────────────────────────────────────────────────────┘
    *┌──────────────────────────────────────────────────────────────┐
    *│ 命名空间: Czar.Cms.Core.Repository                                   
    *│ 类    名: BaseRepository                                      
    *└──────────────────────────────────────────────────────────────┘
    */
    using Czar.Cms.Core.DbHelper;
    using Czar.Cms.Core.Options;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Text;
    using System.Threading.Tasks;
    using Dapper;
    
    namespace Czar.Cms.Core.Repository
    {
        public class BaseRepository<T, TKey> : IBaseRepository<T, TKey> where T : class
        {
            protected DbOpion _dbOpion;
            protected IDbConnection _dbConnection;
    
            //public BaseRepository(DbOpion dbOpion)
            //{
            //    _dbOpion = dbOpion ?? throw new ArgumentNullException(nameof(DbOpion));
            //    _dbConnection = ConnectionFactory.CreateConnection(_dbOpion.DbType, _dbOpion.ConnectionString);
            //}
    
            #region 同步
    
            public T Get(TKey id) => _dbConnection.Get<T>(id);
            public IEnumerable<T> GetList() => _dbConnection.GetList<T>();
    
            public IEnumerable<T> GetList(object whereConditions) => _dbConnection.GetList<T>(whereConditions);
    
            public IEnumerable<T> GetList(string conditions, object parameters = null) => _dbConnection.GetList<T>(conditions, parameters);
    
            public IEnumerable<T> GetListPaged(int pageNumber, int rowsPerPage, string conditions, string orderby, object parameters = null)
            {
                return _dbConnection.GetListPaged<T>(pageNumber, rowsPerPage, conditions, orderby, parameters);
            }
            public int? Insert(T entity) => _dbConnection.Insert(entity);
            public int Update(T entity) => _dbConnection.Update(entity);
    
            public int Delete(TKey id) => _dbConnection.Delete<T>(id);
    
            public int Delete(T entity) => _dbConnection.Delete(entity);
            public int DeleteList(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null)
            {
                return _dbConnection.DeleteList<T>(whereConditions, transaction, commandTimeout);
            }
    
            public int DeleteList(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)
            {
                return _dbConnection.DeleteList<T>(conditions, parameters, transaction, commandTimeout);
            }
            public int RecordCount(string conditions = "", object parameters = null)
            {
                return _dbConnection.RecordCount<T>(conditions, parameters);
            }
            #endregion
    
            #region 异步
            public async Task<T> GetAsync(TKey id)
            {
                return await _dbConnection.GetAsync<T>(id);
            }
    
            public async Task<IEnumerable<T>> GetListAsync()
            {
                return await _dbConnection.GetListAsync<T>();
            }
    
            public async Task<IEnumerable<T>> GetListAsync(object whereConditions)
            {
                return await _dbConnection.GetListAsync<T>(whereConditions);
            }
    
            public async Task<IEnumerable<T>> GetListAsync(string conditions, object parameters = null)
            {
                return await _dbConnection.GetListAsync<T>(conditions, parameters);
            }
            public async Task<IEnumerable<T>> GetListPagedAsync(int pageNumber, int rowsPerPage, string conditions, string orderby, object parameters = null)
            {
                return await _dbConnection.GetListPagedAsync<T>(pageNumber, rowsPerPage, conditions, orderby, parameters);
            }
            public async Task<int?> InsertAsync(T entity)
            {
                return await _dbConnection.InsertAsync(entity);
            }
            public async Task<int> UpdateAsync(T entity)
            {
                return await _dbConnection.UpdateAsync(entity);
            }
            public async Task<int> DeleteAsync(TKey id)
            {
                return await _dbConnection.DeleteAsync(id);
            }
    
            public async Task<int> DeleteAsync(T entity)
            {
                return await _dbConnection.DeleteAsync(entity);
            }
    
    
            public async Task<int> DeleteListAsync(object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null)
            {
                return await _dbConnection.DeleteListAsync<T>(whereConditions, transaction, commandTimeout);
            }
    
            public async Task<int> DeleteListAsync(string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)
            {
                return await DeleteListAsync(conditions, parameters, transaction, commandTimeout);
            }
            public async Task<int> RecordCountAsync(string conditions = "", object parameters = null)
            {
                return await _dbConnection.RecordCountAsync<T>(conditions, parameters);
            }
            #endregion
    
            #region IDisposable Support
            private bool disposedValue = false; // 要检测冗余调用
    
            protected virtual void Dispose(bool disposing)
            {
                if (!disposedValue)
                {
                    if (disposing)
                    {
                        // TODO: 释放托管状态(托管对象)。
                    }
    
                    // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                    // TODO: 将大型字段设置为 null。
    
                    disposedValue = true;
                }
            }
    
            // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
            // ~BaseRepository() {
            //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            //   Dispose(false);
            // }
    
            // 添加此代码以正确实现可处置模式。
            public void Dispose()
            {
                // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
                Dispose(true);
                // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
                // GC.SuppressFinalize(this);
            }
            #endregion
        }
    }
    

你没看错?我在16号就已经写好了,为什么这么晚才写博客分享出来呢?因为我懒~~~

  1. 这里需要注意,需要安装SimpleCRUD的Nuget包。另外其他的仓储方法只需要继承这个接口以及实现就能够实现基本的增删改查操作了。这里你应该会想,既然继承就能实现,那何不写一个仓储的代码生成器来进行生成呢?说干就干,下面我们就来实现仓储的代码生成器

仓储层代码生成器

上篇生成数据库实体的代码生成器不知道大家看了没有,这里我们只需要在根据每个数据库表生成数据库实体的实体顺带着生成下仓储接口以及仓储代码就可以了。有了思路,我们就撸起袖子加油干吧

  1. 先写一下仓储接口代码生成器的模板,如下所示:

1545225197161

  1. 再写一下仓储层的代码实现,这里需要注意一下,需要根据注入的IOptionsSnapshot来生成_dbOpion以及_dbConnection,上面留给大家的思考题答案就在这里,如下所示:

    /**
    *┌──────────────────────────────────────────────────────────────┐
    *│ 描    述:{Comment}接口实现                                                    
    *│ 作    者:{Author}                                            
    *│ 版    本:1.0    模板代码自动生成                                                
    *│ 创建时间:{GeneratorTime}                             
    *└──────────────────────────────────────────────────────────────┘
    *┌──────────────────────────────────────────────────────────────┐
    *│ 命名空间: {RepositoryNamespace}                                  
    *│ 类    名: {ModelName}Repository                                      
    *└──────────────────────────────────────────────────────────────┘
    */
    using Czar.Cms.Core.DbHelper;
    using Czar.Cms.Core.Options;
    using Czar.Cms.Core.Repository;
    using Czar.Cms.IRepository;
    using Czar.Cms.Models;
    using Microsoft.Extensions.Options;
    using System;
    
    namespace {RepositoryNamespace}
    {
        public class {ModelName}Repository:BaseRepository<{ModelName},{KeyTypeName}>, I{ModelName}Repository
        {
            public {ModelName}Repository(IOptionsSnapshot<DbOpion> options)
            {
                _dbOpion =options.Get("CzarCms");
                if (_dbOpion == null)
                {
                    throw new ArgumentNullException(nameof(DbOpion));
                }
                _dbConnection = ConnectionFactory.CreateConnection(_dbOpion.DbType, _dbOpion.ConnectionString);
            }
    
        }
    }
  2. 接着就是代码生成器生成IRepository以及生成Repository的代码了!这部分代码如下图所示:

1545225567381

1545225578141

测试代码

  1. 重新执行下代码生成器的代码,测试的具体代码我已经放在GitHub上了,这里就不贴出来了,直接上生成结果如下图所示:

1545225741822

  1. 如上图所示:一次性生成了Models以及Repository,IRepository的代码,然后到每个文件夹里面把对应的代码拷贝到对应的项目里面吧。然后我们随便打开一下仓储以及仓储接口看下生成后的代码如下所示:

    /**
    *┌──────────────────────────────────────────────────────────────┐
    *│ 描    述:文章分类                                                    
    *│ 作    者:yilezhu                                              
    *│ 版    本:1.0   模板代码自动生成                                              
    *│ 创建时间:2018-12-18 13:28:43                           
    *└──────────────────────────────────────────────────────────────┘
    *┌──────────────────────────────────────────────────────────────┐
    *│ 命名空间: Czar.Cms.IRepository                                   
    *│ 接口名称: IArticleCategoryRepository                                      
    *└──────────────────────────────────────────────────────────────┘
    */
    using Czar.Cms.Core.Repository;
    using Czar.Cms.Models;
    using System;
    
    namespace Czar.Cms.IRepository
    {
        public interface IArticleCategoryRepository : IBaseRepository<ArticleCategory, Int32>
        {
        }
    }
/**
*┌──────────────────────────────────────────────────────────────┐
*│ 描    述:文章分类接口实现                                                    
*│ 作    者:yilezhu                                            
*│ 版    本:1.0    模板代码自动生成                                                
*│ 创建时间:2018-12-18 13:28:43                             
*└──────────────────────────────────────────────────────────────┘
*┌──────────────────────────────────────────────────────────────┐
*│ 命名空间: Czar.Cms.Repository.SqlServer                                  
*│ 类    名: ArticleCategoryRepository                                      
*└──────────────────────────────────────────────────────────────┘
*/
using Czar.Cms.Core.DbHelper;
using Czar.Cms.Core.Options;
using Czar.Cms.Core.Repository;
using Czar.Cms.IRepository;
using Czar.Cms.Models;
using Microsoft.Extensions.Options;
using System;

namespace Czar.Cms.Repository.SqlServer
{
    public class ArticleCategoryRepository:BaseRepository<ArticleCategory,Int32>, IArticleCategoryRepository
    {
        public ArticleCategoryRepository(IOptionsSnapshot<DbOpion> options)
        {
            _dbOpion =options.Get("CzarCms");
            if (_dbOpion == null)
            {
                throw new ArgumentNullException(nameof(DbOpion));
            }
            _dbConnection = ConnectionFactory.CreateConnection(_dbOpion.DbType, _dbOpion.ConnectionString);
        }

    }
}
  1. 在仓储层以及仓储接口层添加对Czar.Cms.Core的引用,当然你也可以通过Nuget包来进行安装

    Install-Package Czar.Cms.Core -Version 0.1.3
  2. 最后在测试代码中进行测试,这里以ArticleCategoryRepository为例进行测试:

    [Fact]
    public void TestBaseFactory()
    {
     IServiceProvider serviceProvider = BuildServiceForSqlServer();
     IArticleCategoryRepository categoryRepository = serviceProvider.GetService<IArticleCategoryRepository>();
     var category = new ArticleCategory
     {
         Title = "随笔",
         ParentId = 0,
         ClassList = "",
         ClassLayer = 0,
         Sort = 0,
         ImageUrl = "",
         SeoTitle = "随笔的SEOTitle",
         SeoKeywords = "随笔的SeoKeywords",
         SeoDescription = "随笔的SeoDescription",
         IsDeleted = false,
     };
     var categoryId = categoryRepository.Insert(category);
     var list = categoryRepository.GetList();
     Assert.True(1 == list.Count());
     Assert.Equal("随笔", list.FirstOrDefault().Title);
     Assert.Equal("SQLServer", DatabaseType.SqlServer.ToString(), ignoreCase: true);
     categoryRepository.Delete(categoryId.Value);
     var count = categoryRepository.RecordCount();
     Assert.True(0 == count);
  3. 测试结果如下所示,都已经测试成功了:

1545226136210

开原地址

这个系列教程的源码我会开放在GitHub以及码云上,有兴趣的朋友可以下载查看!觉得不错的欢迎Star

GitHub:https://github.com/yilezhu/Czar.Cms

码云:https://gitee.com/yilezhu/Czar.Cms

如果你觉得这个系列对您有所帮助的话,欢迎以各种方式进行赞助,当然给个Star支持下也是可以滴!另外一种最简单粗暴的方式就是下面这种直接关注我们的公众号了
第一时间收到更新推送。

总结

一路走来,已经更新到第十二篇了,到这里大伙已经可以基于这个Dapper的封装进行自己的业务系统的开发了!当然接下来我会继续完成我们既定的CMS系统的业务功能开发,接下来可以用来分享的东西就很少了,所以我更多的是开发然后把代码更新到GitHub以及码云上,想看最新的代码就获取dev分支的代码,有问题的可以提issue或者群里讨论!敬请期待吧!

相关文章:

  • PythonR量化 金融之路
  • 第二十章:异步和文件I/O.(二十二)
  • 2018年度总结
  • 第二十章:异步和文件I/O.(二十三)
  • 使用.Net Core+IView+Vue集成上传图片功能
  • 三分钟教你同步 Visual Studio Code 设置
  • 《快速阅读术》
  • 容器中 Java 应用程序的内存和 CPU 如何分配?看这一篇就够了!
  • 北斗三号系列核心芯片
  • Hive日期函数笔记
  • 21-Python与设计模式--备忘录模式
  • mysql-connector-java 6版本的jdbc连接问题
  • Android FM模块学习之四源码解析(一)
  • 冲刺第四天 1.4 FRI
  • 有关java中static关键的重写问题
  • 2017 年终总结 —— 在路上
  • Bootstrap JS插件Alert源码分析
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • Invalidate和postInvalidate的区别
  • JavaScript 基础知识 - 入门篇(一)
  • jQuery(一)
  • leetcode386. Lexicographical Numbers
  • MobX
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • rc-form之最单纯情况
  • ViewService——一种保证客户端与服务端同步的方法
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 力扣(LeetCode)357
  • 码农张的Bug人生 - 见面之礼
  • 前端性能优化——回流与重绘
  • 区块链技术特点之去中心化特性
  • 使用SAX解析XML
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • ​渐进式Web应用PWA的未来
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net core 6 集成和使用 mongodb
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .NET业务框架的构建
  • .so文件(linux系统)
  • @private @protected @public
  • @RequestMapping 的作用是什么?
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [100天算法】-二叉树剪枝(day 48)