.Net core 搭建 仓储模式+SqlsugarORM+AutoFac 您所在的位置:网站首页 webapi连接数据库的常用方法 .Net core 搭建 仓储模式+SqlsugarORM+AutoFac

.Net core 搭建 仓储模式+SqlsugarORM+AutoFac

2023-10-29 12:03| 来源: 网络整理| 查看: 265

一、为什么使用仓储模式

个人觉得仓储模式就是升级版的三层架构,里面多了接口之间的调用,就好像仓库管理员,只是负责把仓库里面的东西交给客户,也无需知道客户要做什么,反之客户也无需知道东西在哪里,怎么存放的,需要的时候就跟管理员索要就可以了,这样就是低耦合,就算管理员换人了,客户的流程也无需做出改变,反之亦然。

实际做一遍就一目了然了。

第一步:先把类库创建好

Common类库,公共类库,放一些公共的类和方法,比如,Helper类 字符串转换,编码格式这些。

IRepositry、Repository仓储层,负责处理数据 就是ADO。net那套东西。

IService、Service 业务服务层,三层架构的BLL。

Model 存放实体类

 

 仓储层,创建ITestRepository和TestRepository,这里我们先不连接数据库,下面讲到ORM的时候在连库。

然后在服务层,创建ITestService和TestService类

 

 代码如下,最好不要复制粘贴,自己一个一个创建,这样能更好的了解,哪个类库是做什么的,要怎么做

using System; namespace WebApi.Core.IRepository { public interface ITestRepository { /// /// 求和,这里就是定义一下具体实现在 TestRepository /// /// /// /// int Sum(int i, int j); } } using System; using WebApi.Core.IRepository; namespace WebApi.Core.Repository { /// /// 仓储具体实现类,继承仓储接口类 /// public class TestRepository:ITestRepository { /// /// 求和,仓储实现,这个过程就是访问数据库得到数据,并且返回 /// /// /// /// public int Sum(int i, int j) { return i + j; } } } using System; namespace WebApi.Core.IService { /// /// 业务服务接口层 /// public interface ITestService { /// /// 求和声明 /// /// /// /// int SumService(int i, int j); } } using System; using WebApi.Core.IRepository; using WebApi.Core.IService; using WebApi.Core.Repository; namespace WebApi.Core.Service { public class TestService:ITestService { //这里如果要用到仓储,需要先创建对象,就好像要知道管理员是谁,这个先这么写,后期改成AutoFac的 ITestRepository test = new TestRepository(); /// /// 求和,调用仓储的求和方法,把参数传递给仓储 /// /// /// /// public int SumService(int i, int j) { return test.Sum(i,j); } } }

 好了一个简单的仓储模式算是搭建完成了,接下来我们测试一下,创建一个Controller名字随便取,在里面添加如下代码

/// /// 测试仓储模式,求和表示层 /// /// /// /// [HttpPost] public int SumService(int i, int j) { //引用service层 ITestService testService = new TestService(); return testService.SumService(i,j); }

F5启动一下,我们测试一下,从测试结果看,是没有任何问题的

 

 

 接下来,我们在仓储模式下增加IOC,上面写的时候会发现一些new 实体的 代码,这样的耦合性就很强了,所以需要使用IOC模式来处理这种耦合,这里我们用.net架构比较常用的Autofac

Nuget包引入两个 Autofac.Extras.DynamicProxy、Autofac.Extensions.DependencyInjection

新建一个类来存放Autofac注册Module,如下代码

using Autofac; using Autofac.Extras.DynamicProxy; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; namespace WebApi.Core.Api.SetUpService { /// /// Autofac注册服务类 /// public class AutofacModuleRegister:Autofac.Module { /// /// 重写Load函数 /// /// protected override void Load(ContainerBuilder builder) { //注册Service var assemblysServices = Assembly.Load("Webapi.Core.Service"); builder.RegisterAssemblyTypes(assemblysServices) .InstancePerDependency()//默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象 .AsImplementedInterfaces()//是以接口方式进行注入,注入这些类的所有的公共接口作为服务(除了释放资源) .EnableInterfaceInterceptors(); //引用Autofac.Extras.DynamicProxy;应用拦截器 //注册Repository var assemblysRepository = Assembly.Load("Webapi.Core.Repository"); builder.RegisterAssemblyTypes(assemblysRepository) .InstancePerDependency()//默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象 .AsImplementedInterfaces()//是以接口方式进行注入,注入这些类的所有的公共接口作为服务(除了释放资源) .EnableInterfaceInterceptors(); //引用Autofac.Extras.DynamicProxy;应用拦截器 } } }

在startup.cs文件中,增加一个方法,用来配置Autofac服务容器,在Configure方法下面,新建如下代码

/// /// 注册Autofac容器 /// /// public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterModule(new AutofacModuleRegister()); }

在program.cs 文件中 初始化一下实例代码如下

public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //这里是替换容器的,微软默认的注入方式是DI,替换成autofac实例 .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); });

到此 我们的注册就算完成了,接下来我们使用一下,如下图,我们上面练习仓储的时候,new 了一个仓储的实例,现在我们来改变一下

 

 

 改成如下代码

public class TestService:ITestService { //这里如果要用到仓储,需要先创建对象,就好像要知道管理员是谁,这个先这么写,后期改成AutoFac的 //ITestRepository test = new TestRepository(); //改造成Autofac注入方式,声明一个仓储常量 private readonly ITestRepository test; //构造函数注入 public TestService(ITestRepository testRepository) { test = testRepository; } /// /// 求和,调用仓储的求和方法,把参数传递给仓储 /// /// /// /// public int SumService(int i, int j) { return test.Sum(i,j); } }

testController这里也有一个new 也需要变化一下

 

 

 改成如下代码

/// /// 测试仓储模式控件 /// public class TestRepositoryController : BaseController { //声明一个常量 private readonly ITestService testService; //构造函数注入 service public TestRepositoryController(ITestService testS) { testService = testS; } /// /// 测试仓储模式,求和表示层 /// /// /// /// [HttpPost] public int SumService(int i, int j) { return testService.SumService(i,j); } }

接下来我们F5启动项目,测试一下,注入是否已完成,是否会报错。从结果上看木有问题啊,哎真希望报错,踩踩坑啊。这也太顺利了

 

 

 还有一个问题,就是如果一个接口被好多服务继承了,依赖注入会怎么处理,会注入哪个服务呢?我们来测试一下

首先在ITestService 里面在添加一个方法

/// /// 返回支付类型 /// /// string payType();

然后在创建一个服务来继承ITestService接口

using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IService; namespace WebApi.Core.Service { public class TestPayService:ITestService {

    ///     /// 测试一个接口多个实例下的依赖注入     ///     ///

        public string payType()

{ return "微信"; } public int SumService(int i, int j) { return 1; } } }

在TestService也要加一个方法

/// /// 测试一个接口多个实例下的依赖注入 /// /// public string payType() { return "支付宝"; }

在TestRepositoryController 下添加一个接口

/// /// 测试一个接口多个实例下的依赖注入 /// /// [HttpGet] public string payType() { return testService.payType(); }

按F5我们看一下结果,可以看到返回的始终是 支付宝,不管调用多少次,如果我想要微信怎么办呢,或者两个都显示。

 

 其实很简单的,需要在startup.cs 的ConfigureServices 加一段代码

public void ConfigureServices(IServiceCollection services) { //注册AppSettings读取类 services.AddSingleton(new AppSettings(Configuration)); //注册Swagger服务 services.AddSwaggerSetup(); //jwt授权验证 services.AddAuthorizationJwtSetUp(); services.AddControllers(); //同一个接口两个实现,依赖注入 services.AddTransient(); services.AddTransient(); }

然后在TestRepositoryController的构造函数修改一下

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using WebApi.Core.IService; using WebApi.Core.Service; namespace WebApi.Core.Api.Controllers { /// /// 测试仓储模式控件 /// public class TestRepositoryController : BaseController { //声明一个常量 private readonly ITestService testService; private readonly ITestService testPayService; //构造函数注入 service 这里使用的就是一对多注入 public TestRepositoryController(IEnumerable testS) { testService = testS.FirstOrDefault(x => x.GetType().Name == "TestService"); testPayService = testS.FirstOrDefault(x=>x.GetType().Name == "TestPayService"); } /// /// 测试仓储模式,求和表示层 /// /// /// /// [HttpPost] public int SumService(int i, int j) { return testService.SumService(i,j); } /// /// 测试一个接口多个实例下的依赖注入 /// /// [HttpGet] public string payType() { return testService.payType()+";"+testPayService.payType(); } } }

然后我们运行F5看一下结果,是没问题的,当然这种写法,会根据业务需求来定,我个人觉得不会经常出现,如果遇到了 会用就行。

 

 还有一个属性注入,但是.NET如果需要用属性注入的话,属性就需要public暴露出去,所以推荐使用构造函数注入。

下面我们继续 Sqlsugar + 改造一下仓储,变成异步的。我们这边用的数据是oracle,首先创建一个表 名字随便起一个

 

 

 我们在Repository 和 model层中引入 Nuget包 sqlSugarCore

然后修改一下UserModel 代码如下

using SqlSugar; using System; namespace WebApi.Core.Model { /// /// 用户实体类 注意这个SugarTable要改成你自己的表名字不然会报错哦 /// [SugarTable("testcoreuser")] public class UsersModel { /// /// id /// [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int UserId { get; set; } /// /// 姓名 /// public string UserName { get; set; } /// /// 年龄 /// public int? Age { get; set; } } }

我们在Repository层中新建一个DbContext类,和BaseDBConfig 类

 

 

 

 

 

 代码如下

using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using WebApi.Core.Model;

namespace WebApi.Core.Repository.SqlSugar{

public class DbContext where T : class, new() { public DbContext() { Db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = BaseDBConfig.ConnectionString, DbType = DbType.SqlServer, InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息 IsAutoCloseConnection = true,//开启自动释放模式 }); //调式代码 用来打印SQL Db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine(sql + "\r\n" + Db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); Console.WriteLine(); }; } //注意:不能写成静态的 public SqlSugarClient Db;//用来处理事务多表查询和复杂的操作 public SimpleClient CurrentDb { get { return new SimpleClient(Db); } }//用来操作当前表的数据 public SimpleClient UserDb { get { return new SimpleClient(Db); } }//用来处理User表的常用操作 }} using System; using System.Collections.Generic; using System.Text; namespace WebApi.Core.Repository.SqlSugar { public class BaseDBConfig { /// /// 数据库连接字符串oracle /// public static string ConnectionString { get; set; } } }

然后在 startup.cs 的ConfigureServices() 方法中读取 appsettings.json 配置的数据

 

 

 接下来我们优化一下仓储模式,先创建一个仓储基类 IBaseRepository.cs

 

 

 代码如下

using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; namespace WebApi.Core.IRepository.Base { /// /// 基类接口,其他接口继承该接口 /// /// public interface IBaseRepository where TEntity : class { /// /// 根据ID查询 /// /// /// Task QueryByID(object objId); /// /// 添加 /// /// /// Task Add(TEntity model); /// /// 修改 /// /// /// Task Update(TEntity model); /// /// 删除 /// /// /// Task DeleteByIds(object[] ids); } }

在创建IUserRepository 然后继承IBaseRepository 代码如下

using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IRepository.Base; using WebApi.Core.Model; namespace WebApi.Core.IRepository { public interface IUserRepository:IBaseRepository { } }

同样的操作,需要在Repository做一遍

 

 

 创建一个BaseRepository和UserRepository代码如下,异步的不要随便加Task.Run() 会有意想不到的问题。会有一些人不知道where 后面是做什么的,其实就是对泛型的约束

class 是表示传过来的 必须是类,new()表示 类型参数必须有一个公有的,无参数的构造方法.当和别的约束一起使用的时候,new()约束必须放在最后

using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using WebApi.Core.IRepository.Base; using WebApi.Core.Repository.SqlSugar; namespace WebApi.Core.Repository.Base { /// /// 基类实现 /// /// public class BaseRepository : DbContext, IBaseRepository where TEntity : class, new() { /// /// 写入实体数据 /// /// /// public async Task Add(TEntity model) { //这里需要注意的是,如果使用了Task.Run()就会导致 sql语句日志无法记录改成下面的 //var i = await Task.Run(() => Db.Insertable(model).ExecuteCommand()); var i = await Db.Insertable(model).ExecuteCommandAsync(); return i>0; } /// /// 根据ID删除 /// /// /// public async Task DeleteByIds(object[] ids) { var i = await Db.Deleteable().In(ids).ExecuteCommandAsync(); return i > 0; } /// /// 根据ID查询一条数据 /// /// /// public async Task QueryByID(object objId) { return await Db.Queryable().InSingleAsync(objId); } /// /// 更新实体数据 /// /// /// public async Task Update(TEntity model) { //这种方式会以主键为条件 var i = await Db.Updateable(model).ExecuteCommandAsync(); return i > 0; } } } using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IRepository; using WebApi.Core.Model; using WebApi.Core.Repository.Base; namespace WebApi.Core.Repository { public class UserRepository:BaseRepository,IUserRepository { } }

仓储层都有了 基类,那么service怎么可以没有呢,跟仓储差不多

 

 

 4个类的代码就全部放在一个里面了,如果要复制,别全部复制,要分批,还是不建议复制粘贴

using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; namespace WebApi.Core.IService.Base { public interface IBaseService where TEntity:class { /// /// 根据ID列表删除 /// /// /// Task DeleteByIds(object[] ids); /// /// 根据ID查询 /// /// /// Task QueryByID(object objId); /// /// 添加实体 /// /// /// Task Add(TEntity model); /// /// 更新实体 /// /// /// Task Update(TEntity model); } } using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using WebApi.Core.IRepository.Base; using WebApi.Core.IService.Base; using WebApi.Core.Repository.Base; namespace WebApi.Core.Service.Base { /// /// 服务基类 /// /// public class BaseService : IBaseService where TEntity : class, new() {

      private readonly IBaseRepository baseDal;

      //这里使用依赖注入

      public BaseService(IBaseRepository baseRepository)       {         baseDal = baseRepository;       }

/// /// 写入实体 /// /// /// public async Task Add(TEntity model) { return await baseDal.Add(model); } /// /// 根据ID删除 /// /// /// public async Task DeleteByIds(object[] ids) { return await baseDal.DeleteByIds(ids); } /// /// 根据ID查询 /// /// /// public async Task QueryByID(object objId) { return await baseDal.QueryByID(objId); } /// /// 更新实体 /// /// /// public async Task Update(TEntity model) { return await baseDal.Update(model); } } } using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IService.Base; using WebApi.Core.Model; namespace WebApi.Core.IService { public interface IUserService:IBaseService { } } using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IService; using WebApi.Core.Model; using WebApi.Core.Service.Base; namespace WebApi.Core.Service { public class UserService:BaseService,IUserService {      //这里我们要把实参传到baseService 不然会报错

      public UserService(IBaseRepository baseRepository):base(baseRepository)       {

      }

} }

接下来 我们测试一下,新增一个UserTest控制器代码如下

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using WebApi.Core.IService; using WebApi.Core.Model; namespace WebApi.Core.Api.Controllers { /// /// 用户表测试ORMSqlSuggr /// public class UserORMController : BaseController { //声明一个常量 private readonly IUserService userService; /// /// 通过构造函数依赖注入 /// /// public UserORMController(IUserService userSer) { userService = userSer; } /// /// 根据id获取数据 /// /// 参数id /// [HttpPost] public async Task GetUser(int id) { UsersModel user = await userService.QueryByID(id); return Ok(user); } /// /// 添加数据 /// /// 参数id /// [HttpPost] public async Task Add(UsersModel user) { var count = await userService.Add(user); return Ok(count); } /// /// 更新数据 /// /// 参数id /// [HttpPost] public async Task Update(UsersModel user) { var sucess = await userService.Update(user); return Ok(sucess); } /// /// 删除数据 /// /// 参数id /// [HttpPost] public async Task Delete(object[] ids) { var sucess = await userService.DeleteByIds(ids); return Ok(sucess); } } }

终于完工了,我们来F5运行看一下,数据已经有了,剩下的各位可以试一下,建议可以自己试着改一下看看各种效果

 

 

 

 删除可以批量传入ID

 

 可以看到 sql语句也打印出来了,是在DBContext 里面 使用 Db.Aop.OnLogExecuting 这句话是 sql执行同时记录

 接下来我们把SqlSugar下的常用查询方法试一下(有太多了,需要用到的在去搜索一下就可以,万变不离其宗,就是lambda表达式和一些内置函数的支持,跳转到源码估计也就是ADO.net那些东西)

在仓储层增加一个方法,IUserRepository和UserRepository ,服务层 IUserService 和UserService 也需要添加,然后在Controller中添加一个接口调用

这里也是把东西放在一起了,其中UserRepository重点看一下

using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IRepository.Base; using WebApi.Core.Model; namespace WebApi.Core.IRepository { public interface IUserRepository:IBaseRepository { /// /// 测试sqlSugar 常用语句 /// void testSqlSugar(); } } using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IRepository; using WebApi.Core.Model; using WebApi.Core.Repository.Base; namespace WebApi.Core.Repository { public class UserRepository:BaseRepository,IUserRepository { /// /// 测试sqlSugar 常用语句 /// public void testSqlSugar() { //查询一个集合 List list = Db.Queryable().ToList(); //把list转换成json串打印输出 Console.WriteLine(JsonConvert.SerializeObject(list)); //打印集合的数量 Console.WriteLine(list.Count); //直接查询并转换成json 跟上面的输出结果一样,没有任何区别 var testJson = Db.Queryable().ToJson(); Console.WriteLine(testJson); //根据条件查询单条数据 UsersModel usermodel = Db.Queryable().Single(t=>t.Age==30); //判断不为空,打印其中一个字段值 Console.WriteLine(usermodel?.UserName +"----------"); //根据主键查询单条数据 usermodel = Db.Queryable().InSingle(1); //判断不为空,打印其中一个字段值 Console.WriteLine(usermodel?.UserName + "----------"); //查询姓名为张三的第一条记录 usermodel = Db.Queryable().Where(t => t.UserName == "张三").First(); Console.WriteLine(usermodel?.UserName + "----------"); //判断数据是否存在 bool exists = Db.Queryable().Any(t=>t.UserName=="小兰"); Console.WriteLine(exists.ToString()); //模糊查询 testJson = Db.Queryable().Where(t => t.UserName.Contains("李")).ToJson(); Console.WriteLine(testJson); //以xx结尾 或开始 testJson = Db.Queryable().Where(t => t.UserName.EndsWith("三") || t.UserName.StartsWith("李")).ToJson(); Console.WriteLine(testJson); } } } using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IService.Base; using WebApi.Core.Model; namespace WebApi.Core.IService { public interface IUserService:IBaseService { /// /// 测试sqlSugar 常用语句 /// void testSqlSugar(); } } using System; using System.Collections.Generic; using System.Text; using WebApi.Core.IRepository; using WebApi.Core.IRepository.Base; using WebApi.Core.IService; using WebApi.Core.Model; using WebApi.Core.Service.Base; namespace WebApi.Core.Service { public class UserService:BaseService,IUserService { //声明常量 private readonly IUserRepository userService; public UserService(IBaseRepository baseRepository, IUserRepository usersSer):base(baseRepository) { userService = usersSer; } /// /// 测试sqlSugar 常用语句 /// public void testSqlSugar() { userService.testSqlSugar(); } } } using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using WebApi.Core.IService; using WebApi.Core.Model; namespace WebApi.Core.Api.Controllers { /// /// 用户表测试ORMSqlSuggr /// public class UserORMController : BaseController { //声明一个常量 private readonly IUserService userService; /// /// 通过构造函数依赖注入 /// /// public UserORMController(IUserService userSer) { userService = userSer; } /// /// 根据id获取数据 /// /// 参数id /// [HttpPost] public async Task GetUser(int id) { UsersModel user = await userService.QueryByID(id); return Ok(user); } /// /// 添加数据 /// /// 参数id /// [HttpPost] public async Task Add(UsersModel user) { var count = await userService.Add(user); return Ok(count); } /// /// 更新数据 /// /// 参数id /// [HttpPost] public async Task Update(UsersModel user) { var sucess = await userService.Update(user); return Ok(sucess); } /// /// 删除数据 /// /// 参数id /// [HttpPost] public async Task Delete(object[] ids) { var sucess = await userService.DeleteByIds(ids); return Ok(sucess); } /// /// 测试sqlSugar 常用语句 /// /// [HttpGet] public IActionResult testSqlSugar() { userService.testSqlSugar(); return Ok("true"); } } }

这里代码问题解决后,F5启动看看结果

 

 运行没问题,没有报错,然后我们看一下控制台输出,可以看到输出的sql语句和 打印出的结果,这里可以跟代码比对一下。也可以自己搜索一些分页啊等等的,可以看一下结果

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有