• ASP.NET Core模块化前后端分离快速开发框架介绍之3、数据访问模块介绍


    源码

    GitHub:https://github.com/iamoldli/NetModular

    演示地址

    地址:https://nm.iamoldli.com
    账户:admin
    密码:admin

    前端框架演示地址(临时)

    地址:http://nm.demo.iamoldli.com/index.html
    账户:admin
    密码:admin

    目录

    1、开篇
    2、快速创建一个业务模块
    3、数据访问模块介绍
    4、模块化实现思路

    简介

    NetModular 的数据访问模块是基于 Dapper 扩展的轻量级的ORM,它本身是完全独立的,可以在任何项目中直接使用。在NetModular中也提供了扩展,能够完美的与模块化集成在一起。

    支持的功能

    • [x] 支持SqlServer、MySql、SQLite数据库
    • [x] 基础的CRUD方法
    • [x] 批量添加、删除、修改
    • [x] 修改指定列
    • [x] Lamdba表达式支持
    • [x] 多表连接查询
    • [x] 分页查询
    • [x] 分组查询
    • [x] 仓储模式
    • [x] 工作单元
    • [x] 自定义表名、列名
    • [x] 支持同步/异步方法

    使用方法

    NetModular 本身已经做好了集成,所以业务模块中,可以直接写代码,不用考虑注入的问题,如果想要了解它的集成逻辑的,可以查看Data.AspNetCore

    Data.AspNetCore

    Node: 数据库上下文、仓储和工作单元的注入方式采用的是Scoped

    1、添加数据库上下文

    数据库上下文需要继承DbContext

        public class MallDbContext : DbContext
        {
            public MallDbContext(IDbContextOptions options) : base(options)
            {
            }
        }
    

    2、创建实体

    实体需要继承IEntity接口,在NetModular中,已经提供了几个通用的实体基类,并且内部已经实现了对应的功能,比如EntityBase

        public class EntityBase<TKey> : Entity<TKey>
        {
            /// <summary>
            /// 创建时间
            /// </summary>
            public DateTime CreatedTime { get; set; } = DateTime.Now;
    
            /// <summary>
            /// 创建人
            /// </summary>
            public Guid CreatedBy { get; set; }
    
            /// <summary>
            /// 修改时间
            /// </summary>
            public DateTime ModifiedTime { get; set; } = DateTime.Now;
    
            /// <summary>
            /// 修改人
            /// </summary>
            public Guid ModifiedBy { get; set; }
    
            /// <summary>
            /// 创建人名称
            /// </summary>
            [Ignore]
            public string Creator { get; set; }
    
            /// <summary>
            /// 修改人
            /// </summary>
            [Ignore]
            public string Modifier { get; set; }
        }
    

    可以看到 EntityBase 已经包含了CreatedTime,CreatedBy,ModifiedTime,ModifiedBy这四个实体属性,通过实体继承了EntityBase,那么该实体也包含了这个属性,同时NetModular内部已经实现了在添加,修改时,自动设置对应的创建人和修改人编号,所以你不需要你去考虑这些事情了。

    另外还有包含软删除功能的EntityWithSoftDelete以及包含上面两个实体功能的EntityBaseWithSoftDelete两个实体,这些都已经封装好了,可以直接用。

    Node: 上面的三个实体基类都会继承自Entity,该实体包含了一个主键Id,主键类型支持Guid(默认)、Int、Long三种类型。

    可以通过Table特性,设置实体对应的表名称

    以下是一个产品的实体示例:

    [Table("Product")]
    public partial class ProductEntity : EntityBase
    {
        /// <summary>
        /// 标题
        /// </summary>
        public string Title { get; set; }
    
        /// <summary>
        /// 价格
        /// </summary>
        public decimal Price { get; set; }
    
        /// <summary>
        /// 库存
        /// </summary>
        public int Store { get; set; }
    
        /// <summary>
        /// 状态
        /// </summary>
        public ProductStatus Status { get; set; }
    }
    

    实体扩展类:

    Node: 实体扩展类中的属性,必须添加Ignore特性,否则属性会被当成表的列处理。

    public partial class ProductEntity
    {
        /// <summary>
        /// sku列表
        /// </summary>
        [Ignore]
        public List<Guid> Skus { get; set; }
    }
    

    3、添加仓储接口

    仓储接口必须继承IRepository<>接口

    /// <summary>
    /// 产品仓储接口
    /// </summary>
    public interface IProductRepository : IRepository<ProductEntity>
    {
        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task<IList<ProductEntity>> Query(ProductQueryModel model);
    }
    

    4、添加查询模型

    查询模型包含查询条件,需要继承QueryModel类,该类包含了分页相关的信息

    public class ProductQueryModel : QueryModel
    {
        public string Title { get; set; }
    }
    

    5、添加仓储实现

    仓储实现需要继承抽象仓储RepositoryAbstract<>,不同数据库的仓储实现,需要放到不同的目录中。因为不同的数据库难免会有一些查询,所以我们采用先实现一种数据库的实现,然后其它数据实现直接继承它,对于有查询的方法,采用覆写的方式实现。

    public class ProductRepository : RepositoryAbstract<ProductEntity>, IProductRepository
    {
        public ProductRepository(IDbContext context) : base(context)
        {
        }
    
        public async Task<IList<ProductEntity>> Query(ProductQueryModel model)
        {
            //分页
            var paging = model.Paging();
    
            var query = Db.Find();
            query.WhereIf(model.Title.NotNull(), m => m.Title.Contains(model.Title));
    
            //设置默认排序
            if (!paging.OrderBy.Any())
            {
                query.OrderByDescending(m => m.Id);
            }
    
            var list = await query.PaginationAsync(paging);
            model.TotalCount = paging.TotalCount;
            return list;
        }
    }
    

    上面的例子是一个最简单的分页查询,到此数据访问的代码就写完了,剩下的就是在服务层调用就行了。

    其它用法说明

    1、CRUD

    基础的CRUD在RepositoryAbstract中已经实现了,所以可以直接在服务中调用

    新增

    _repository.AddAsync(entity);
    

    批量新增

    _repository.AddAsync(entities);
    

    删除

    _repository.DeleteAsync(id);
    

    软删除

    _repository.SoftDeleteAsync(id);
    

    修改

    _repository.UpdateAsync(entity);
    

    获取

    _repository.GetAsync(id);
    

    获取所有

    _repository.GetAllAsync()
    

    是否存在

    _repository.ExistsAsync(m => m.Title.Contains("test"))
    

    批量修改

    /// <summary>
    /// 批量修改状态
    /// </summary>
    /// <param name="ids"></param>
    /// <param name="status"></param>
    /// <returns></returns>
    public Task<bool> UpdateStatus(List<Guid> ids, ProductStatus status)
    {
        return Db.Find(m => ids.Contains(m.Id)).UpdateAsync(m => new ProductEntity { Status = status });
    }
    

    批量删除

    /// <summary>
    /// 批量删除
    /// </summary>
    /// <param name="title"></param>
    /// <returns></returns>
    public Task<bool> Delete(string title)
    {
        return Db.Find(m => m.Title.Contains(title)).DeleteAsync();
    }
    

    表连接查询

    public async Task<IList<ProductEntity>> Query(ProductQueryModel model)
    {
        //分页
        var paging = model.Paging();
    
        var query = Db.Find();
        query.WhereIf(model.Title.NotNull(), m => m.Title.Contains(model.Title));
    
        //设置默认排序
        if (!paging.OrderBy.Any())
        {
            query.OrderByDescending(m => m.Id);
        }
    
        var list = await query.LeftJoin<AccountEntity>((x, y) => x.CreatedBy == y.Id)
            .Select((x, y) => new { x, Creator = y.Name })
            .PaginationAsync(paging);
    
        model.TotalCount = paging.TotalCount;
        return list;
    }
    

    分组查询

    
    Db.Find().GroupBy(m => new { m.Status }).Select(m => new { m.Key.Status, Count = m.Count() });
    
    

    工作单元

    工作单元在服务中注入使用

    private readonly IUnitOfWork _uow;
    public ArticleService(IUnitOfWork<MalDbContext> uow)
    {
        _uow = uow;
    }
    

    然后通过BeginTransaction方法开启事务,Commit方法提交事务,Rollback方法回滚事务

    _uow.BeginTransaction();
    var result = await _accountRepository.AddAsync(account);
    if (result)
    {
        if (model.Roles != null && model.Roles.Any())
        {
            var accountRoleList = model.Roles.Select(m => new AccountRoleEntity { AccountId = account.Id, RoleId = m }).ToList();
            if (await _accountRoleRepository.AddAsync(accountRoleList))
            {
                _uow.Commit();
                return ResultModel.Success();
            }
        }
        else
        {
            _uow.Commit();
            return ResultModel.Success();
        }
    }
    

    好了,数据库访问的用法大致就是这样~

  • 相关阅读:
    P1829 [国家集训队]Crash的数字表格 / JZPTAB 莫比乌斯反演
    Luogu P1447 [NOI2010]能量采集 数论??欧拉
    Luogu P2522 [HAOI2011]Problem b 莫比乌斯反演
    Luogu P2257 YY的GCD 莫比乌斯反演
    [笔记] 数论函数小记
    [笔记] 线性筛小记
    Luogu P1092 虫食算 爆搜
    Luogu P1066 2^k进制数 组合数学
    Luogu P1641 [SCOI2010]生成字符串 组合数学
    Luogu P2532 [AHOI2012]树屋阶梯 卡特兰数
  • 原文地址:https://www.cnblogs.com/oldli/p/10910247.html
Copyright © 2020-2023  润新知