本篇我将带着大家一起来对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;
} }

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

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

CRUD及分页泛型方法的实现

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

  2. 新建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
    }
    }
  3. 然后创建一个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号就已经写好了,为什么这么晚才写博客分享出来呢?因为我懒~~~~~~~

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

仓储层代码生成器

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

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

  2. 再写一下仓储层的代码实现,这里需要注意一下,需要根据注入的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);
    } }
    }
  3. 接着就是代码生成器生成IRepository以及生成Repository的代码了!这部分代码如下图所示:

测试代码

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

  2. 如上图所示:一次性生成了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);
    } }
    }
  3. 在仓储层以及仓储接口层添加对Czar.Cms.Core的引用,当然你也可以通过Nuget包来进行安装

    Install-Package Czar.Cms.Core -Version 0.1.3
  4. 最后在测试代码中进行测试,这里以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);
  5. 测试结果如下所示,都已经测试成功了:

开原地址

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

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

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

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

第一时间收到更新推送。

总结

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

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

  1. .NET Core实战项目之CMS 第十四章 开发篇-防止跨站请求伪造(XSRF/CSRF)攻击处理

    通过 ASP.NET Core,开发者可轻松配置和管理其应用的安全性. ASP.NET Core 中包含管理身份验证.授权.数据保护.SSL 强制.应用机密.请求防伪保护及 CORS 管理等等安全方面 ...

  2. .NET Core实战项目之CMS 第十五章 各层联动工作实现增删改查业务

    连着两天更新叙述性的文章大家可别以为我转行了!哈哈!今天就继续讲讲我们的.NET Core实战项目之CMS系统的教程吧!这个系列教程拖得太久了,所以今天我就以菜单部分的增删改查为例来讲述下我的项目分层 ...

  3. .NET Core实战项目之CMS 第十六章 用户登录及验证码功能实现

    前面为了方便我们只是简单实现了基本业务功能的增删改查,但是登录功能还没有实现,而登录又是系统所必须的,得益于 ASP.NET Core的可扩展性因此我们很容易实现我们的登录功能.今天我将带着大家一起来 ...

  4. .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9977862.html 写在前面 千呼万唤始出来,首先,请允许我长吸一口气!真没想到一份来自28岁老程序员 ...

  5. .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练

    写在前面 上篇文章我带着大家通过分析了一遍ASP.NET Core的源码了解了它的启动过程,然后又带着大家熟悉了一遍配置文件的加载方式,最后引出了依赖注入以及控制反转的概念!如果大家把前面几张都理解了 ...

  6. .NET Core实战项目之CMS 第九章 设计篇-白话架构设计

    前面两篇文章给大家介绍了我们实战的CMS系统的数据库设计,源码也已经上传到服务器上了.今天我们就好聊聊架构设计,在开始之前先给大家分享一下这几天我一直在听的<从零开始学架构>里面关于架构设 ...

  7. .NET Core实战项目之CMS 第十一章 开发篇-数据库生成及实体代码生成器开发

    上篇给大家从零开始搭建了一个我们的ASP.NET Core CMS系统的开发框架,具体为什么那样设计我也已经在第十篇文章中进行了说明.不过文章发布后很多人都说了这样的分层不是很合理,什么数据库实体应该 ...

  8. .NET Core实战项目之CMS 第十三章 开发篇-在MVC项目结构介绍及应用第三方UI

    作为后端开发的我来说,前端表示真心玩不转,你如果让我微调一个位置的样式的话还行,但是让我写一个很漂亮的后台的话,真心做不到,所以我一般会选择套用一些开源UI模板来进行系统UI的设计.那如何套用呢?今天 ...

  9. .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...

随机推荐

  1. 禁止Centos7系统yum自动下载更新

    安装Centos7后,系统自动更新状态默认为开启,若禁止系统自动更新需要手动关闭. 1.进入yum目录  [root@localhost ~]$ cd /etc/yum 2.编辑yum-cron.co ...

  2. python第二十二天(面向对象)

    1.面向过程编程: 核心就是过程两个字,过程是指解决问题的步骤,即先干什么后做什么. 基于该思想编写程序就好比在编写一条流水线,是一种机械式的思维方式 优点:复杂的问题流程化.进而简单化 缺点:可扩展 ...

  3. python中用xlsxwriter创建图表

    缺点:xlsxwriter不能对已存在的Excel进行编辑插入图标   生成图标需要: 1.先准备数据 2.将数据插入到excel中 3.根据插入的数据生成图表 这里的生成excel主要分为准备多维数 ...

  4. CF987B - High School: Become Human

    Year 2118. Androids are in mass production for decades now, and they do all the work for humans. But ...

  5. PCA:利用PCA(四个主成分的贡献率就才达100%)降维提高测试集辛烷值含量预测准确度并《测试集辛烷值含量预测结果对比》—Jason niu

    load spectra; temp = randperm(size(NIR, 1)); P_train = NIR(temp(1:50),:); T_train = octane(temp(1:50 ...

  6. Ubuntu 18.04 系统配置 NPM环境和mysql数据库问题解决

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效. 今天我就为大家 使用 Ubun ...

  7. TypeScript 函数-Lambads 和 this 关键字的使用

    let people = { name:["a","b","c","d"], /* getName:function() ...

  8. 用OleDb导入Excel时提示驱动错误问题解决办法

    导入格式为xls的excel文件,发生了错误 未处理System.Data.OleDb.OleDbException HResult=-2147467259 Message=外部数据库驱动程序 (1) ...

  9. WinccFlexible 同一个项目创建多个connections

    在一个WinccFlexible 项目中,可以创建多个通讯连接,以满足不同的接口要求. 但是需要在控制面板上 Set PG/PC Interface中添加新的连接,并绑定对应的网卡即可.

  10. 一些 NSArray 的基本操作代码例子

    一些 NSArray 的基本操作代码例子 数组可以说是软件开发人员每天都要面对的基本操作,下面就分享一些 NSArray 的基本操作代码例子供苹果开发初学者参考,每段代码第一行会以注释方式说明该段代码 ...