当前位置:Gxlcms > 数据库问题 > .Net core 搭建 仓储模式+SqlsugarORM+AutoFac(转)

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

时间:2021-07-01 10:21:17 帮助过:645人阅读

using System;

namespace WebApi.Core.IRepository
{
    public interface ITestRepository
    {
        /// <summary>
        /// 求和,这里就是定义一下具体实现在 TestRepository
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        int Sum(int i, int j);
    }
}



using System;
using WebApi.Core.IRepository;

namespace WebApi.Core.Repository
{
    /// <summary>
    /// 仓储具体实现类,继承仓储接口类
    /// </summary>
    public class TestRepository:ITestRepository
    {
        /// <summary>
        /// 求和,仓储实现,这个过程就是访问数据库得到数据,并且返回
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        public int Sum(int i, int j)
        {
            return i + j;
        }
    }
}



using System;

namespace WebApi.Core.IService
{
    /// <summary>
    /// 业务服务接口层
    /// </summary>
    public interface ITestService
    {
        /// <summary>
        /// 求和声明
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        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();
        /// <summary>
        /// 求和,调用仓储的求和方法,把参数传递给仓储
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        public int SumService(int i, int j)
        {
            return test.Sum(i,j);
        }
    }
}
技术图片

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

技术图片
 /// <summary>
        /// 测试仓储模式,求和表示层
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        [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
{
    /// <summary>
    /// Autofac注册服务类
    /// </summary>
    public class AutofacModuleRegister:Autofac.Module
    {
        /// <summary>
        /// 重写Load函数
        /// </summary>
        /// <param name="builder"></param>
        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方法下面,新建如下代码

技术图片
/// <summary>
        /// 注册Autofac容器
        /// </summary>
        /// <param name="builder"></param>
        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<Startup>();
                });
技术图片

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

技术图片

 

 

 改成如下代码

技术图片
 public class TestService:ITestService
    {
        //这里如果要用到仓储,需要先创建对象,就好像要知道管理员是谁,这个先这么写,后期改成AutoFac的
        //ITestRepository test = new TestRepository();
        //改造成Autofac注入方式,声明一个仓储常量
        private readonly ITestRepository test;
        //构造函数注入
        public TestService(ITestRepository testRepository)
        {
            test = testRepository;
        }

        /// <summary>
        /// 求和,调用仓储的求和方法,把参数传递给仓储
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        public int SumService(int i, int j)
        {
            return test.Sum(i,j);
        }
    }
技术图片

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

技术图片

 

 

 改成如下代码

技术图片
 /// <summary>
    /// 测试仓储模式控件
    /// </summary>
    public class TestRepositoryController : BaseController
    {
        //声明一个常量
        private readonly ITestService testService;
        //构造函数注入 service
        public TestRepositoryController(ITestService testS)
        {
            testService = testS;
        }

        /// <summary>
        /// 测试仓储模式,求和表示层
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        [HttpPost]
        public int SumService(int i, int j)
        {
            return testService.SumService(i,j);
        }
    }
技术图片

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

技术图片

 

 

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

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

/// <summary>
        /// 返回支付类型
        /// </summary>
        /// <returns></returns>
        string payType();

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

技术图片
using System;
using System.Collections.Generic;
using System.Text;
using WebApi.Core.IService;

namespace WebApi.Core.Service
{
    public class TestPayService:ITestService
    {

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

        public string payType()

        {
            return "微信";
        }

        public int SumService(int i, int j)
        {
            return 1;
        }
    }
}
技术图片

在TestService也要加一个方法

技术图片
/// <summary>
        /// 测试一个接口多个实例下的依赖注入
        /// </summary>
        /// <returns></returns>
        public string payType()
        {
            return "支付宝";
        }
技术图片

在TestRepositoryController 下添加一个接口

技术图片
/// <summary>
        /// 测试一个接口多个实例下的依赖注入
        /// </summary>
        /// <returns></returns>
        [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<ITestService, TestPayService>();
            services.AddTransient<ITestService, TestService>();
        }
技术图片

然后在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
{
    /// <summary>
    /// 测试仓储模式控件
    /// </summary>
    public class TestRepositoryController : BaseController
    {
        //声明一个常量
        private readonly ITestService testService;
        private readonly ITestService testPayService;
        //构造函数注入 service 这里使用的就是一对多注入
        public TestRepositoryController(IEnumerable<ITestService> testS)
        {
            testService = testS.FirstOrDefault(x => x.GetType().Name == "TestService");
            testPayService = testS.FirstOrDefault(x=>x.GetType().Name == "TestPayService");
        }

        /// <summary>
        /// 测试仓储模式,求和表示层
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
        [HttpPost]
        public int SumService(int i, int j)
        {
            return testService.SumService(i,j);
        }
        /// <summary>
        /// 测试一个接口多个实例下的依赖注入
        /// </summary>
        /// <returns></returns>
        [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
{
    /// <summary>
    /// 用户实体类 注意这个SugarTable要改成你自己的表名字不然会报错哦
    /// </summary>
    [SugarTable("testcoreuser")]
    public class UsersModel
    {
        /// <summary>
        /// id
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int UserId { get; set; }
        /// <summary>
        /// 姓名
        /// </summary>
        public string UserName { get; set; }
        /// <summary>
        /// 年龄
        /// </summary>
        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<T> 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<T> CurrentDb { get { return new SimpleClient<T>(Db); } }//用来操作当前表的数据

    public SimpleClient<UsersModel> UserDb { get { return new SimpleClient<UsersModel>(Db); } }//用来处理User表的常用操作

}
}
技术图片 技术图片
using System;
using System.Collections.Generic;
using System.Text;

namespace WebApi.Core.Repository.SqlSugar
{
    public class BaseDBConfig
    {
        /// <summary>
        /// 数据库连接字符串oracle
        /// </summary>
        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
{
    /// <summary>
    /// 基类接口,其他接口继承该接口
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public interface IBaseRepository<TEntity> where TEntity : class
    {
        /// <summary>
        /// 根据ID查询
        /// </summary>
        /// <param name="objId"></param>
        /// <returns></returns>
        Task<TEntity> QueryByID(object objId);

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task<bool> Add(TEntity model);

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task<bool> Update(TEntity model);

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        Task<bool> 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<UsersModel>
    {
    }
}
技术图片

同样的操作,需要在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
{
    /// <summary>
    /// 基类实现
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class BaseRepository<TEntity> : DbContext<TEntity>, IBaseRepository<TEntity> where TEntity : class, new()
    {
        /// <summary>
        /// 写入实体数据
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> 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;
        }

        /// <summary>
        /// 根据ID删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task<bool> DeleteByIds(object[] ids)
        {
            var i = await Db.Deleteable<TEntity>().In(ids).ExecuteCommandAsync();
            return i > 0;
        }

        /// <summary>
        /// 根据ID查询一条数据
        /// </summary>
        /// <param name="objId"></param>
        /// <returns></returns>
        public async Task<TEntity> QueryByID(object objId)
        {
            return await Db.Queryable<TEntity>().InSingleAsync(objId);
        }

        /// <summary>
        /// 更新实体数据
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> 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<UsersModel>,IUserRepository
    {

    }
}
技术图片

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

技术图片

 

 

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

技术图片
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace WebApi.Core.IService.Base
{
    public interface IBaseService<TEntity> where TEntity:class
    {
        /// <summary>
        /// 根据ID列表删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        Task<bool> DeleteByIds(object[] ids);

        /// <summary>
        /// 根据ID查询
        /// </summary>
        /// <param name="objId"></param>
        /// <returns></returns>
        Task<TEntity> QueryByID(object objId);

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task<bool> Add(TEntity model);

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>

        Task<bool> 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
{
    /// <summary>
    /// 服务基类
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class BaseService<TEntity> : IBaseService<TEntity> where TEntity : class, new()
    {

      private readonly IBaseRepository<TEntity> baseDal;

      //这里使用依赖注入

      public BaseService(IBaseRepository<TEntity> baseRepository)
      {
        baseDal = baseRepository;
      }

/// <summary>
        /// 写入实体
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> Add(TEntity model)
        {
            return await baseDal.Add(model);
        }

        /// <summary>
        /// 根据ID删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>

        public async Task<bool> DeleteByIds(object[] ids)
        {
            return await baseDal.DeleteByIds(ids);
        }

        /// <summary>
        /// 根据ID查询
        

                  

	 	
                    
                    
                    
                    
                    
                

人气教程排行