前言
首先从网上复制一些关于Dapper的介绍:
Dapper 是StackOverflow开源的一个MiniOrm,优点主要有:开源、轻量、小巧(单文件,代码就一个SqlMapper.cs文件,编译后就40K的一个很小的Dll.),性能和原生ado.net相近。但是由于它自身对linq的支持 ,没有EntityFramework和NHibernate那样好,所以我们在项目中实际使用时,有时需要基于dapper的扩展 (DapperExtensions)来使用第三方扩展的一些方法,实现更丰富的用法支持。
准备工作
演示的测试项目是基于.net core2.1来创建的WebApi接口,同时项目中还使用了Autofac的Ioc容器,首先我们先来看下测试项目的目录结构:
其中核心的类库是AspNetCore.WebApi.ORM,基本是从网上下载的开源项目代码,其中SqlMapper.cs就是Dapper的核心文件。
Dapper原生方法
继续下面的内容之前,我们先来简单看一下Dapper的一些原生的方法,列举几个查询方法如下:
/// <summary> /// 执行SQL返回集合 /// </summary> /// <param name="strSql">sql语句</param> /// <returns></returns> public virtual List<T> Query<T>(string strSql) { using (IDbConnection conn = Connection) { return conn.Query<T>(strSql, null).ToList(); } } /// <summary> /// 执行SQL返回一个对象 /// </summary> /// <param name="strSql">SQL语句</param> /// <returns></returns> public virtual T QueryFirst<T>(string strSql) { using (IDbConnection conn = Connection) { return conn.Query<T>(strSql).FirstOrDefault<T>(); } } /// <summary> /// 执行SQL返回一个对象(异步) /// </summary> /// <param name="strSql">SQL语句</param> /// <returns></returns> public virtual async Task<T> QueryFirstAsync<T>(string strSql) { using (IDbConnection conn = Connection) { var res = await conn.QueryAsync<T>(strSql); return res.FirstOrDefault<T>(); } }
当然本身还有非常多其它的方法,如下图所示,
但这些原生的方法基本都需要传入sql语句作为参数,在某些场景下,如果能支持lambda表达式的查询方式,不用简单的CRUD也要手写sql,这样会方便很多。因此下面就来看一下Dapper的第三方扩展方法
核心代码解读
DapperContext.cs
扩展方法的核心基于DapperContext.cs这个文件,下面列出其核心代码:
namespace Dapper.Data { /// <summary> /// 数据操作基类 /// </summary> public class DapperContext : IDapperContext, IDisposable { #region 初始化 private readonly string connString; private readonly DbProviderFactory dbfactory; /// <summary> /// 初始化 /// </summary> public DapperContext(string connectionString, string providerName) { connString = connectionString; SetDatabaseType(providerName); switch (DBType) { case DatabaseType.SqlServer: dbfactory = SqlClientFactory.Instance; break; case DatabaseType.Oracle: dbfactory = OracleClientFactory.Instance; break; default: break; } } /// <summary> /// 获取当前的数据库连接对象 /// </summary> /// <returns></returns> protected virtual IDbConnection GetConnection() { DbConnection dbconn = dbfactory.CreateConnection(); dbconn.ConnectionString = connString; return dbconn; } /// <summary> /// 数据库驱动类型 /// </summary> public DatabaseType DBType { get; protected set; } #endregion #region IDapperContext 成员 private IDbConnection dbConnection; /// <summary> /// 数据库连接 /// </summary> public IDbConnection Connection { get { if (dbConnection == null) dbConnection = GetConnection(); return dbConnection; } } private IDbTransaction dbTransaction; #endregion } }
BaseDataService.cs
此时我们就可以基于DapperContext来创建Service层,来实现调用了。我们在AspNetCore.WebApi.Service项目里创建一个BaseDataService.cs类(服务层的基类,抽象出一些公共的方法),部分核心代码如下:
namespace AspNetCore.WebApi.Service { public class BaseDataService<T> where T : class, new() { private readonly DapperContext _context; public BaseDataService(DapperContext context) { _context = context; } /// <summary> /// 获取列表 /// </summary> /// <returns></returns> public virtual List<T> GetList(Expression<Func<T, bool>> predicate) { return _context.Set<T>().Select(where: predicate) as List<T>; } /// <summary> /// 添加 /// </summary> /// <param name="item"></param> /// <returns></returns> public bool Add(T item) { var flag = _context.Set<T>().Insert(item); _context.SaveChanges(); return flag; } } }
UserController.cs
最后我们在UserController.cs里实现对服务层的调用,并从数据库里查询出数据返回出去:
namespace AspNetCore.WebApi.Main.Controllers { [Route("api/[controller]/[action]")] [ApiController] public class UserController : BaseController { private readonly BaseDataService<User> _baseUserService = null; private readonly UserService _userService = null; /// <summary> /// 构造函数方式注入服务实例 /// </summary> /// <param name="baseUserService"></param> /// <param name="userService"></param> public UserController(BaseDataService<User> baseUserService, UserService userService) { _baseUserService = baseUserService; _userService = userService; } // GET api/user/FindAll [HttpGet] public ActionResult<ResponseResult<List<User>>> FindAll() { Expression<Func<User, bool>> expression = p => true; var userList = GetList<User>(_baseUserService, expression, c => c.Asc(o => o.LOGIN_NAME)); return userList; } // GET api/user/FindOne?name=xxx [HttpGet] public ResponseResult<User> FindOne(string name) { ResponseResult<User> result = null; { //方式1:通过手动sql方式查询 result = _userService.GetUserByName(name); } { //方式2:通过扩展的方式,结合表达式树的条件查询 Expression<Func<User, bool>> expression = p => true; if (!string.IsNullOrWhiteSpace(name)) { expression = expression.And(c => c.LOGIN_NAME.Equals(name)); } result = Get<User>(_baseUserService, expression, ""); } return result; } /// <summary> /// 新增 /// </summary> /// <param name="user"></param> /// <returns></returns> [HttpPost] public ResponseResult<string> SaveUser(User user) { return Save<User>(_baseUserService, user, c => c.USER_ID.Equals(user.USER_ID), "用户信息保存成功"); } } }
Autofac注入服务实例
到了上面这一步时,还没有结束,我们还需要注册各个服务实例,这里我们使用Autofac来实现依赖注入,下面仍通过代码展示在.net core2.1下如何使用Autofac实现注入。主要是要修改Statup.cs中的RegisterAutofac方法:
namespace AspNetCore.WebApi.Main { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); return RegisterAutofac(services);//注册Autofac } private IServiceProvider RegisterAutofac(IServiceCollection services) { //实例化Autofac容器 var builder = new ContainerBuilder(); builder.Populate(services); //从appsetting.json里获取数据库连接 Dictionary<string, string> keyValues = Configuration.GetSection("ConnectionStrings").Get<Dictionary<string, string>>(); var sqlconn = keyValues.FirstOrDefault(c => c.Key.Equals("SqlConnetionString")).Value; var provider= keyValues.FirstOrDefault(c => c.Key.Equals("ProviderName")).Value; //注册dapper的数据库连接 builder.Register<DapperContext>(c => new DapperContext(sqlconn, provider)).InstancePerDependency(); //注册service程序集 builder.RegisterAssemblyTypes(ServiceHelper.GetExecutingAssembly()).AsImplementedInterfaces().InstancePerDependency(); builder.RegisterAssemblyTypes(ServiceHelper.GetExecutingAssembly()).InstancePerDependency(); //泛型不能自动注入 builder.RegisterGeneric(typeof(BaseDataService<>)).As(typeof(BaseDataService<>)).InstancePerDependency(); //创建容器 var Container = builder.Build(); //第三方IOC接管 core内置DI容器 return new AutofacServiceProvider(Container); } } }
结果展示
我们运行并调试Api接口,可以看到接口被成功调用
总结
由于本文的代码较多,只选择粘贴了一些核心代码(完整示例代码后期会分享到GitHub上,其中SqlMapper及DapperExtensions等文件可以自行搜索下载),目的是为了说明,在使用Dapper的原生方法时,还可以通过自己封装或第三方的扩展方法,从而获得更丰富简便的方式,也增加了代码的可读性。后续在实际的使用过程中将进一步深入的研究~~
评论列表
评论内容: