1.基础框架
领域驱动设计(DDD)
Domain Driven Design:领域层、应用层、展现层、基础设施层
- Domain.Shared:常量,枚举【类似utils】
- Domain:实体,集合根,领域服务,值类型,仓储接口【类似于entities】
- Application.Contracts:应用服务接口和应用层的数据传输对象 (DTO)【类似于service中Interface和dto】
- Application:应用服务接口实现【类似于service中Interface实现】
- EntityFrameworkCore:定义
DbContext并实现.Domain模块中定义的仓储接口【mybatis的orm映射,逆向工程将实体类转为sql脚本】 - DbMigrator:数据库迁移【jdbc操作】
- HttpApi:定义API控制器【Controller】
2.增删改查
在Application层实现Application.Contracts接口具体的业务(增删改查)知识点总结
2.1接口实现
namespace Demo.Books
{
// 使用别人的模块
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
public class BookAppService : [实现上层基类] ,IBookAppService
{
// bookRepository具有mybatis直接与数据库操作的对象【sqlSessionFactory?】返回的是Book对象数据
private readonly IRepository<Book, Guid> bookRepository;
// BookAppService有参构造【初始化bean?】
public BookAppService(IRepository<Book, Guid> _bookRepository)
{
bookRepository = _bookRepository;
}
// TODO CRUD
}
}
2.2分页查询
.GetQueryableAsync()
AsyncExecuter.CountAsync(q) | AsyncExecuter.ToListAsync(q)
ObjectMapper.Map<List<A>,List<B>>(ListA)多表复杂结构需要映射
PagedResultDto<>() | ListResultDto<>()
// 分页查询【GetPageAsync()方法】:GetBookDto前端发送数据,BookDto是返回给前端数据
public async Task<PagedResultDto<BookDto>> GetPageAsync(GetBookDto input)
{
// input校验 GetBookDto中使用注解 [Required]必传字段
if (input.Sorting.IsNullOrWhiteSpace())
{
input.Sorting = "err";
}
// GetQueryableAsync()方法查询数据
var query = await bookRepository.GetQueryableAsync();
// where条件查询过滤【linq语法】
query = query.Where(x => x.BookId == input.BookId);
// AsyncExecuter.CountAsync(q)方法统计查询数量
var totalCount = await AsyncExecuter.CountAsync(query);
if (totalCount <= 0)
{
return new PagedResultDto<BookDto>();
}
// orderby pageby过滤【排序+分页条件】
query = query.OrderBy(input.Sorting).PageBy(input);
// AsyncExecuter.ToListAsync(q)方法将数据库查询数据转List<Book>
var result = await AsyncExecuter.ToListAsync(query);
// ObjectMapper.Map<List<Book>, List<BookDto>>(r))
// List<Book> 转 List<BookDto>
return new PagedResultDto<BookDto>(totalCount,
ObjectMapper.Map<List<Book>, List<BookDto>>(result));
}
/* ObjectMapper.Map映射 */
using AutoMapper;
namespace Demo.Books
{
public class BookAutoMapperProfile : Profile
{
public BookAutoMapperProfile()
{
CreateMap<Book, BookDto>();
// CreateMap<Book, BookDto>().ForMember(...);
CreateMap<SaveBookDto, Book>();
}
}
}
2.3新增和修改
// 新增和修改【SaveAsync()方法】:SaveBookDto前端发送数据,BookDto是返回给前端数据
public async Task<BookDto> SaveAsync(SaveBookDto input)
{
// TODO input校验
if (!input.Id.HasValue)
{
// 新增
return await CreateAsync(input);
}
// 修改
return await UpdateAsync(input);
}
.GetAsync(i) | .InsertAsync(o) | .UpdateAsync(o)
// 新增
private async Task<BookDto> CreateAsync(SaveBookDto input)
{
// new Book,实例化前端传过来的数据
var book = new Book(
GuidGenerator.Create(),
input.Name,
input.Author,
input.Year
input.Infomation);
// 插入数据
book = await bookRepository.InsertAsync(book);
return ObjectMapper.Map<Book, BookDto>(book);
}
// 修改
private async Task<ChannelAccountDto> UpdateAsync(SaveBookDto input)
{
// 获取符合id的数据
var book = await bookRepository.GetAsync(input.Id.Value);
// 将 SaveBookDto 转 Book
book = ObjectMapper.Map(input, Book);
// 修改数据
var editBook = await bookRepository.UpdateAsync(book);
return ObjectMapper.Map<Book, BookDto>(editBook);
}
2.4删除
.DeleteAsync(i)
public async Task DeleteAsync(Guid id)
{
await bookRepository.DeleteAsync(id);
}
2.5测试
在HttpApi模块中的Controller中写restful风格
Swagger集成测试
using Demo.Books;
using Volo.Abp;
namespace Demo.Books.Controllers
{
[Route("api/book")]
[Area("book")]
[RemoteService(Name = "book")]
public class BookController: [基类控制器]
{
// 同理类似于需要注入Bean【这里的是Application.Contracts中的接口】
private readonly IBookAppService bookAppService;
public BookController(IBookAppService _bookAppService)
{
this.bookAppService = _bookAppService;
}
// GetPageAsync测试
[HttpGet]
public async Task<PagedResultDto<BookDto>> GetPageAsync(GetBookDto input)
{
return await bookAppService.GetPageAsync(input);
}
// SaveAsync测试
[HttpPost]
public async Task<BookDto> SaveAsync(SaveBookDto input)
{
return await bookAppService.SaveAsync(input);
}
// DeleteAsync测试
[HttpGet]
[Route("{id}")]
public async Task<BookDto> DeleteAsync(Guid id)
{
return await bookAppService.DeleteAsync(id);
}
}
}
3.常用方法
3.1查询
其他的查询方式:
.GetListAsync()
.GetListAsync(query)
.GetAsync() //查一个
.FirstOrDefaultAsync(query) // 查询条件符合第一条数据
一对多的查询方式:
// 一对多(对象中有对象)
.WithDetailsAsync(x => x.Books)
// EFCore中加:
b.HasMany(x => x.Books).WithOne().HasForeignKey(x => x.UserId);
// Domian中加:
/*User*/
...
public virtual ICollection<Book> Books { get; protected set; }
public virtual void AddBook(IGuidGenerator guidGenerator,Guid bookId,...)
{
Books.Add(new Book(guidGenerator.Create(), bookId, ...));
}
/*Book*/
public class Book : Entity<Guid>
{
...
public virtual GUid UserId {get; protected set;};
...
}
// Where条件中:
x =>UserId.Contains(x.Id)
x.Books.Any(t => t.UserId == x.Id) //Books中多个
3.2父子节点递归树
/// <summary>
/// 递归初始化树
/// </summary>
/// <param name="nodes">结果</param>
/// <param name="parentID">父ID</param>
/// <param name="sources">数据源</param>
private void InitTree(IList<ProductDto> nodes, Guid? parentID, IList<ProductDto> sources)
{
//递归寻找子节点
var tempTree = sources.Where(item => item.ParentId == parentID).ToList();
foreach (ProductDto row in tempTree)
{
var tempNode = new ProductDto()
{
...
Id = row.Id,
ParentId = row.ParentId,
Children = new List<ProductDto>()
};
nodes.Add(tempNode);
InitTree(tempNode.Children, row.Id, sources);
}
}
3.3技巧方法
//将字符串数组string[] a转化成以逗号分隔符的字符串
temp = string.Join(',', input.temp)
//将数组根据逗号分隔成数组
x=>x.temp.Split(',')
//手动分页
var baseList = list.Skip((input.PageNumber - 1) * input.PageSize).Take(input.PageSize).ToList();