Web开发:ABP框架8——仓储写法及其依赖注入的相关介绍

一、仓储

1.使用仓储的好处

2.仓储参考Demo

业务/表仓储

public class BookRepository : IBookRepository, ITransientDependency  //接口依赖注入
{
    private readonly IFreeSql _fsql;

    public BookRepository(IFreeSql fsql)
    {
        _fsql = fsql;
    }

    /// <summary>
    /// 获取FreeSql
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public IFreeSql GetFreeSql()
    {
        return _fsql;
    }

    /// <summary>
    /// 分页查询:Book
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [Route(nameof(GetBookPageListAsync))]
    public async Task<IPageList<BookDto>> GetBookPageListAsync(BookSerachInput input)
    {
        var output = new PageList<BookDto>(new List<BookDto>(), input.PageIndex, input.maxResultCount);
        if (false)
        {
            return output;//不符合要求,返回空数据
        }
        var fsql = GetFreeSql();
        //查表
        var queryList = await fsql.Select<Book>()
                        .Where(x => x.TimePoint.Between(input.StartTime, input.EndTime))
                        .WhereIf(input.StationCodes.Any(), x => input.StationCodes.Contains(x.CityCode))
                        .OrderBy(!string.IsNullOrEmpty(input.orderby), input.orderby)
                        .Page(input.PageIndex, input.maxResultCount)
                        .Count(out var totalCount)
                        .ToListAsync();
        //映射结果
        var dtoList = _objectMapper.Map<List<Book>, List<BookDto>>(queryList);
        return new PageList<BookDto>(dtoList, input.PageIndex, input.maxResultCount, totalCount);
    }

    /// <summary>
    /// Book 单一实体 修改
    /// </summary>
    public async Task<bool> UpdateBookAsync(BookDto input)
    {
        var fsql = GetFreeSql();
        return fsql.Update<BookDto>(input).ExecuteAffrows() != 0;
    }

    /// <summary>
    /// Book 单一实体 保存
    /// </summary>
    public async Task<bool> SaveBookAsync(BookDto input)
    {
        var fsql = GetFreeSql();
        bool isExist = await fsql.Select<Book>().AnyAsync(x => x.Id == input.Id);//【根据实际修改】根据(联合)主键确定唯一性
        if (isExist)
        {
            return await UpdateBookAsync(input);
        }
        return await InsertBookAsync(input);
    }

    /// <summary>
    /// Book 单一实体 插入
    /// </summary>
    public async Task<bool> InsertBookAsync(BookDto input)
    {
        var fsql = GetFreeSql();
        return fsql.Insert(input).ExecuteAffrows() != 0;
    }

    /// <summary>
    /// Book 单一实体 删除
    /// </summary>
    public async Task<bool> DeleteBookAsync(BookDto input)
    {
        var fsql = GetFreeSql();
        return fsql.Delete<BookDto>(input).ExecuteAffrows() != 0;
    }

    /// <summary>
    /// Book 列表 保存
    /// </summary>
    public async Task<bool> SaveBookListAsync(List<BookDto> inputList)
    {
        bool result = true;
        var fsql = GetFreeSql();

        //获取输入主键
        var inputKeyList = inputList.Select(x => x.Id ).Distinct().ToList();

        //根据输入主键获取已存在实体
        var existList = await fsql.Select<Book>().Where(x => inputKeyList.Contains(x.Id)).ToListAsync();

        //获取已存在实体的主键列表
        var existKeyList = existList.Select(x => x.Id).Distinct().ToList();

        // 获取更新列表和插入列表
        var updateList = inputList.Where(x => existKeyList.Contains(x.Id)).ToList();
        var insertList = inputList.Where(x => !existKeyList.Contains(x.Id)).ToList();

        /*联合主键:
            //获取输入主键
            var inputKeyList = inputList.Select(x => new { x.Id , x.BookName }).Distinct().ToList();
            //根据输入主键获取已存在实体
            var existList = await fsql.Select<Book>().Where(x=> inputKeyList.Any(key=>key.Id == x.Id && key.BookName == x.BookName)).ToListAsync();
            //获取已存在实体的主键列表
            var existKeyList = existList.Select(x => new { x.Id, x.BookName }).Distinct().ToList();
            //获取更新列表和插入列表
            var updateList = inputList.Where(x => existKeyList.Contains(new { x.Id, x.BookName })).ToList();
            var insertList = inputList.Where(x => !existKeyList.Contains(new { x.Id, x.BookName })).ToList();
       */

        // 使用批量更新和批量插入方法
        bool updateSuccess = await UpdateBookListAsync(updateList);  // 批量更新
        bool insertSuccess = await InsertBookListAsync(insertList);  // 批量插入

        return updateSuccess && insertSuccess; // 返回是否全部成功
    }

    /// <summary>
    /// Book 列表 修改
    /// </summary>
    public async Task<bool> UpdateBookListAsync(List<BookDto> input)
    {
        var fsql = GetFreeSql();
        return fsql.Update<BookDto>(input).ExecuteAffrows() != 0;
    }

    /// <summary>
    /// Book 列表 插入
    /// </summary>
    public async Task<bool> InsertBookListAsync(List<BookDto> input)
    {
        var fsql = GetFreeSql();
        return fsql.Insert(input).ExecuteAffrows() != 0;
    }

    /// <summary>
    /// Book 列表 删除
    /// </summary>
    public async Task<bool> DeleteBookListAsync(List<BookDto> input)
    {
        var fsql = GetFreeSql();
        return fsql.Delete<BookDto>(input).ExecuteAffrows() != 0;
    }

}

泛型仓储

public class CrudRepository : ICrudRepository,ITransientDependency  
{
     private readonly IFreeSql _freeSql;

     /// <summary>
     /// 1.需数据库配置主键、实体特性配置主键和映射列名
     /// 2.含单条数据、批量数据实体CRUD
     /// </summary>
     public CrudRepository(IFreeSql freeSql)
     {
         _freeSql = freeSql;
     }

     /// <summary>
     /// 获取FreeSql
     /// </summary>
     public IFreeSql GetFreeSql()
     {
         var fsql = xxxx;//这里请自行配置
         return fsql;
     }

     public async Task<bool> Insert<T>(T entity) where T : class 
     {
         var fsql = GetFreeSql();
         return await fsql.Insert(entity).ExecuteAffrowsAsync() != 0;
     }
     public async Task<bool> Insert<T>(List<T> enList) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Insert(enList).ExecuteAffrowsAsync() != 0;
     }

     public async Task<bool> Update<T>(T entity) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Update<T>().SetSource(entity).ExecuteAffrowsAsync() != 0;
     }
     public async Task<bool> Update<T>(List<T> enList) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Update<T>().SetSource(enList).ExecuteAffrowsAsync() != 0;
     }

     public async Task<bool> Delete<T>(T entity) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Delete<T>(entity).ExecuteAffrowsAsync() != 0;
     }

     public async Task<bool> Delete<T>(List<T> enList) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Delete<T>(enList).ExecuteAffrowsAsync() != 0;
     }

     public async Task<bool> DeleteByExp<T>(Expression<Func<T, bool>> exp) where T : class
     {
         var fsql = GetFreeSql();
         var effCount = await fsql.Delete<T>().Where(exp).ExecuteAffrowsAsync();
         return effCount != 0;
     }

     public async Task<List<T>> GetList<T>(Expression<Func<T, bool>> exp=null) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Select<T>().WhereIf(exp!=null,exp).ToListAsync();
     }

     public async Task<T> FirstOrDefault<T>(Expression<Func<T, bool>> exp) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Select<T>().Where(exp).ToOneAsync();
     }

     public async Task<bool> Any<T>(Expression<Func<T, bool>> exp) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Select<T>().AnyAsync(exp);
     }

     public async Task<int> Count<T>(Expression<Func<T, bool>> exp) where T : class
     {
        var fsql = GetFreeSql();
        await fsql.Select<T>().Where(exp).Count(out var totals).ToListAsync();
        return Convert.ToInt32(totals);
     }

     /// <summary>
     /// 查表返回单列(入参1:字段,入参2:条件)
     /// </summary>
     /// <returns></returns>
     public async Task<List<V>> GetSingleList<T, V>(Expression<Func<T, V>> method1, Expression<Func<T, bool>> method2=null) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Select<T>().WhereIf(method2!=null,method2).ToListAsync<V>(method1);
     }        
     
     /// <summary>
     /// 【重载】查表返回单列(V=string),返回的是List<string>()
     /// </summary>
     /// <returns></returns>
     public async Task<List<string>> GetSingleList<T>(Expression<Func<T, string>> method1, Expression<Func<T, bool>> method2=null) where T : class
     {
         var fsql = GetFreeSql();
         return await fsql.Select<T>().WhereIf(method2!=null,method2).ToListAsync<string>(method1);
     }

    /// <summary>
    /// 保存实体
    /// (先删后插方案)
    /// </summary>
    public async Task<bool> Save<T>(T entity) where T : class
    {
        await Delete(entity);
        return await Insert(entity);
    }

    /// <summary>
    /// 保存列表
    /// (先删后插方案)
    /// </summary>
    public async Task<bool> BatchSave<T>(List<T> enlist) where T : class
    {
        await Delete(enlist);
        return await Insert(enlist);
    }
 }

单例控制台

public class Crud
{
    private static IFreeSql _freesql;  // 改为静态字段,确保单例

    /// <summary>
    /// 设置FreeSql实例
    /// </summary>
    public static void SetFreesql(IFreeSql freesql)
    {
         _freesql = freesql;
    }

    /// <summary>
    /// 获取FreeSql实例
    /// </summary>
    public static IFreeSql GetFreeSql()
    {
        if (_freesql == null)
        {
            throw new InvalidOperationException("FreeSql instance has not been set.");
        }
        return _freesql;
    }

    public static bool Insert<T>(T entity) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Insert(entity).ExecuteAffrows() != 0;
    }

    public static bool Insert<T>(List<T> enList) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Insert(enList).ExecuteAffrows() != 0;
    }

    public static bool Update<T>(T entity) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Update<T>().SetSource(entity).ExecuteAffrows() != 0;
    }

    public static bool Update<T>(List<T> enList) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Update<T>().SetSource(enList).ExecuteAffrows() != 0;
    }

    public static bool Delete<T>(T entity) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Delete<T>(entity).ExecuteAffrows() != 0;
    }

    public static bool Delete<T>(List<T> enList) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Delete<T>(enList).ExecuteAffrows() != 0;
    }

    public static bool DeleteByExp<T>(Expression<Func<T, bool>> exp) where T : class
    {
        var fsql = GetFreeSql();
        var effCount = fsql.Delete<T>().Where(exp).ExecuteAffrows();
        return effCount != 0;
    }

    public static List<T> GetList<T>(Expression<Func<T, bool>> exp = null) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Select<T>().WhereIf(exp != null, exp).ToList();
    }

    public static T FirstOrDefault<T>(Expression<Func<T, bool>> exp) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Select<T>().Where(exp).ToOne();
    }

    public static bool Any<T>(Expression<Func<T, bool>> exp) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Select<T>().Any(exp);
    }

    public static int Count<T>(Expression<Func<T, bool>> exp) where T : class
    {
        var fsql = GetFreeSql();
        var totals = fsql.Select<T>().Where(exp).Count();
        return Convert.ToInt32(totals);
    }

    /// <summary>
    /// 查表返回单列(入参1:字段,入参2:条件)
    /// </summary>
    public static List<V> GetSingleList<T, V>(Expression<Func<T, V>> method1, Expression<Func<T, bool>> method2 = null) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Select<T>().WhereIf(method2 != null, method2).ToList<V>(method1);
    }

    /// <summary>
    /// 【重载】查表返回单列(V=string),返回的是List<string>()
    /// </summary>
    public static List<string> GetSingleList<T>(Expression<Func<T, string>> method1, Expression<Func<T, bool>> method2 = null) where T : class
    {
        var fsql = GetFreeSql();
        return fsql.Select<T>().WhereIf(method2 != null, method2).ToList<string>(method1);
    }

    /// <summary>
    /// 保存实体
    /// (先删后插方案)
    /// </summary>
    public static bool Save<T>(T entity) where T : class
    {
        Delete(entity);
        return  Insert(entity);
    }

    /// <summary>
    /// 保存列表
    /// (先删后插方案)
    /// </summary>
    public static bool BatchSave<T>(List<T> enlist) where T : class
    {
        Delete(enlist);
        return Insert(enlist);
    }
}

二、依赖注入

1.依赖注入的好处

2.什么模块需要用依赖注入

        服务、仓储、拦截器、配置服务等

3.【重点】如何进行依赖注入

(1)实现接口

        高层服务可以继承ApplicationService,注意高层服务作为接口对外开放需要三要素请求标签、路由、公开修饰符public),若是仅限本服务使用,则方法可不配置请求标签、路由,用private修饰即可。【本质:继承ApplicationService,相当于实现了ITransientDependency】

public class MyAppService : ApplicationService
{
    private readonly IMyService _myService;

    public MyAppService(IMyService myService)
    {
        _myService = myService;
    }

    //省略方法
}

         底层服务可以实现 ITransientDependency,因为底层服务仅涉及业务逻辑(BBL),几乎不需要集成非常多的操作

public class MyService : ITransientDependency , IBookService
{
    private readonly IMyService _myService;

    public MyService(IMyService myService)
    {
        _myService = myService;
    }

    //省略方法
}

(2)特性注入

        基本只有底层服务才会这样,因为高层代码继承ApplicationService,是因为该接口自动注入了很多有用的工具。

[Dependency(ServiceLifetime.Transient)]
public class MyService : IBookService
{
    private readonly IMyService _myService;

    public MyService(IMyService myService)
    {
        _myService = myService;
    }

    //省略方法
}

(3)手动注入

        在相应的模块类写如下代码:

public class BookStoreApplicationModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<AbpAutoMapperOptions>(options =>
        {
            options.AddMaps<BookStoreApplicationModule>();
        });

        context.Services.AddTransient<IBookService, BookService>(); // 手动注册服务,注意两者是实现和接口的关系
    }
}

         手动注入我认为的好处是,可以通过配置来轻松替换依赖的实现,这使得你可以在不同的环境(如生产环境、测试环境或开发环境)中使用不同的服务实现。

        例如我的邮件服务,有一个是给生产环境用的,一个是给开发环境用的。

public interface IEmailService
{
    void SendEmail(string to, string subject, string body);
}

public class SmtpEmailService : IEmailService
{
    public void SendEmail(string to, string subject, string body)
    {
        // 真实的发送邮件逻辑
        Console.WriteLine($"Email sent to {to} with subject {subject}");
    }
}

public class FakeEmailService : IEmailService
{
    public void SendEmail(string to, string subject, string body)
    {
        // 只是模拟发送邮件,不进行实际操作
        Console.WriteLine($"[Fake] Email simulated to {to} with subject {subject}");
    }
}

        配置模块类,我可以这么写(注意,GetEnvironmentVariable获取的是系统环境变量Key=ASPNETCORE_ENVIRONMENT对应的值,因此,生产环境中只需配置环境变量即可,没有这个环境变量,则读launchSettings.json的内容或者默认为开发环境):

public class MyApplicationModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

        if (environment == "Development" || environment == "Production")
        {
            // 在生产或开发环境中,使用真实的邮件服务
            context.Services.AddTransient<IEmailService, SmtpEmailService>();
        }
        else if (environment == "Test")
        {
            // 在测试环境中,使用模拟邮件服务
            context.Services.AddTransient<IEmailService, FakeEmailService>();
        }
    }
}

三、三种生命周期

四、高层服务继承ApplicationService的好处

        可以直接使用下面自动注入的服务,无需另外注入

1.UnitOfWorkManager
using (var unitOfWork = UnitOfWorkManager.Begin())
{
    try
    {
        // 数据库操作...
        await unitOfWork.CompleteAsync(); // 提交事务
    }
    catch (Exception)
    {
        await unitOfWork.RollbackAsync(); // 回滚事务
        throw; // 重新抛出异常
    }
}

2.AsyncExecuter
private readonly IRepository<Student> _student;//除了运用在仓储外,还可以运用在IOrderedEnumerable<T> 中
var list2 = await AsyncExecuter.ToListAsync(_student);//异步操作(等待),必须查完才执行后面代码,不阻塞线程【推荐】
var list3 = _student.ToList();//同步操作,必须查完才执行后面的代码

3.ObjectMapper
// 将实体列表转换为DTO列表
var dtolist = ObjectMapper.Map<List<Book>, List<BookDto>>(entitylist);

4.LoggerFactory 
// 使用 LoggerFactory 创建一个 Logger
var logger = LoggerFactory.CreateLogger<MyService>();
logger.LogInformation("xxxxxxxxxxx");

5.CurrentTenant
// 获取当前租户信息
var tenantId = CurrentTenant.GetId();

6.CurrentUser
// 获取当前用户ID
var userId = CurrentUser.UserId; 

7.GuidGenerator
var guidId = GuidGenerator.Create();//生成Guid(ABP框架经过优化可以产生连续的GUID.这对于关系数据库中的聚集索引非常重要.)

8.也顺带继承了ITransientDependency,底层服务继承它可以完成依赖注入,避免出现找不到服务的问题

我认为比较重要的好处:

继承ApplicationService = IAvoidDuplicateCrossCuttingConcerns(日志记录) + IValidationEnabled(接口输入验证)+IUnitOfWorkEnabled(事务)+ IAuditingEnabled(审计)+IGlobalFeatureCheckingEnabled(特性检查)+  ITransientDependency(依赖注入)

(1)继承了ApplicationService,可用映射  ObjectMapper.Map

(2)继承了ITransientDependency,保证了服务被正确注入到依赖容器,高层代码才能调用这个底层代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值