源码
GitHub: https://github.com/iamoldli/NetModular
演示地址
地址: http://129.211.40.240:6220/
账户: admin
密码: admin
前端框架演示地址 (临时)
地址:
账户: admin
密码: admin
目录
1, 开篇
2, 快速创建一个业务模块
3, 数据访问模块介绍
简介
NetModular 的数据访问模块是基于 https://github.com/StackExchange/Dapper 扩展的轻量级的 ORM, 它本身是完全独立的, 可以在任何项目中直接使用. 在 NetModular 中也提供了扩展, 能够完美的与模块化集成在一起.
支持的功能
[x] 支持 SqlServer,MySQL,SQLite 数据库
[x] 基础的 CRUD 方法
[x] 批量添加, 删除, 修改
[x] 修改指定列
[x] Lamdba 表达式支持
[x] 多表连接查询
[x] 分页查询
[x] 分组查询
[x] 仓储模式
[x] 工作单元
[x] 自定义表名, 列名
[x] 支持同步 / 异步方法
使用方法
NetModular 本身已经做好了集成, 所以业务模块中, 可以直接写代码, 不用考虑注入的问题, 如果想要了解它的集成逻辑的, 可以查看 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();
- }
- }
好了, 数据库访问的用法大致就是这样~
来源: https://www.cnblogs.com/oldli/p/10910247.html