介绍

评论本来是要放到标签里面去讲的,但是因为上一章东西有点多了,我就没放进去,这一章单独拿出来,内容不多大家自己写写就可以,也算是对前面讲解的一个小练习吧。

相关注释我也加在代码上面了,大家看看代码都可以理解。

评论仓储接口和实现

  1. public interface ICommentRepository : IBasicRepository<Comment, Guid>
  2. {
  3. /// <summary>
  4. /// 根据文章Id 获取评论
  5. /// </summary>
  6. /// <param name="postId"></param>
  7. /// <param name="cancellationToken"></param>
  8. /// <returns></returns>
  9. Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default);
  10. /// <summary>
  11. /// 根据文章Id 获取评论数量
  12. /// </summary>
  13. /// <param name="postId"></param>
  14. /// <param name="cancellationToken"></param>
  15. /// <returns></returns>
  16. Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default);
  17. /// <summary>
  18. /// 根据评论Id 下面的子获取评论
  19. /// </summary>
  20. /// <param name="id"></param>
  21. /// <param name="cancellationToken"></param>
  22. /// <returns></returns>
  23. Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default);
  24. Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default);
  25. }
  26. public class EfCoreCommentRepository:EfCoreRepository<CoreDbContext, Comment, Guid>,ICommentRepository
  27. {
  28. public EfCoreCommentRepository(IDbContextProvider<CoreDbContext> dbContextProvider) : base(dbContextProvider)
  29. {
  30. }
  31. public async Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
  32. {
  33. return await (await GetDbSetAsync())
  34. .Where(a => a.PostId == postId)
  35. .OrderBy(a => a.CreationTime)
  36. .ToListAsync(GetCancellationToken(cancellationToken));
  37. }
  38. public async Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
  39. {
  40. return await (await GetDbSetAsync())
  41. .CountAsync(a => a.PostId == postId, GetCancellationToken(cancellationToken));
  42. }
  43. public async Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default)
  44. {
  45. return await (await GetDbSetAsync())
  46. .Where(a => a.RepliedCommentId == id).ToListAsync(GetCancellationToken(cancellationToken));
  47. }
  48. public async Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default)
  49. {
  50. var recordsToDelete = await (await GetDbSetAsync()).Where(pt => pt.PostId == id).ToListAsync(GetCancellationToken(cancellationToken));
  51. (await GetDbSetAsync()).RemoveRange(recordsToDelete);
  52. }
  53. }

评论接口和Dto

  1. public interface ICommentAppService : IApplicationService
  2. {
  3. Task<List<CommentWithRepliesDto>> GetHierarchicalListOfPostAsync(Guid postId);
  4. Task<CommentWithDetailsDto> CreateAsync(CreateCommentDto input);
  5. Task<CommentWithDetailsDto> UpdateAsync(Guid id, UpdateCommentDto input);
  6. Task DeleteAsync(Guid id);
  7. }
  8. public class CommentWithRepliesDto
  9. {
  10. public CommentWithDetailsDto Comment { get; set; }
  11. public List<CommentWithDetailsDto> Replies { get; set; } = new List<CommentWithDetailsDto>();
  12. }
  13. public class CommentWithDetailsDto : FullAuditedEntityDto<Guid>
  14. {
  15. public Guid? RepliedCommentId { get; set; }
  16. public string Text { get; set; }
  17. public BlogUserDto Writer { get; set; }
  18. }
  19. public class CreateCommentDto
  20. {
  21. public Guid? RepliedCommentId { get; set; }
  22. public Guid PostId { get; set; }
  23. [Required]
  24. public string Text { get; set; }
  25. }
  26. public class UpdateCommentDto
  27. {
  28. [Required]
  29. public string Text { get; set; }
  30. }

接口实现


  1. public class CommentAppService : CoreAppService, ICommentAppService
  2. {
  3. private IUserLookupService<IdentityUser> UserLookupService { get; }
  4. private readonly ICommentRepository _commentRepository;
  5. private readonly IGuidGenerator _guidGenerator;
  6. public CommentAppService(ICommentRepository commentRepository, IGuidGenerator guidGenerator, IUserLookupService<IdentityUser> userLookupService)
  7. {
  8. _commentRepository = commentRepository;
  9. _guidGenerator = guidGenerator;
  10. UserLookupService = userLookupService;
  11. }
  12. public async Task<List<CommentWithRepliesDto>> GetHierarchicalListOfPostAsync(Guid postId)
  13. {
  14. // 获取评论数据
  15. var comments = await GetListOfPostAsync(postId);
  16. #region 对评论的作者进行赋值
  17. var userDictionary = new Dictionary<Guid, BlogUserDto>();
  18. foreach (var commentDto in comments)
  19. {
  20. if (commentDto.CreatorId.HasValue)
  21. {
  22. var creatorUser = await UserLookupService.FindByIdAsync(commentDto.CreatorId.Value);
  23. if (creatorUser != null && !userDictionary.ContainsKey(creatorUser.Id))
  24. {
  25. userDictionary.Add(creatorUser.Id, ObjectMapper.Map<IdentityUser, BlogUserDto>(creatorUser));
  26. }
  27. }
  28. }
  29. foreach (var commentDto in comments)
  30. {
  31. if (commentDto.CreatorId.HasValue && userDictionary.ContainsKey((Guid)commentDto.CreatorId))
  32. {
  33. commentDto.Writer = userDictionary[(Guid)commentDto.CreatorId];
  34. }
  35. }
  36. #endregion
  37. var hierarchicalComments = new List<CommentWithRepliesDto>();
  38. #region 包装评论数据格式
  39. // 评论包装成2级(ps:前面的查询根据时间排序,这里不要担心子集在父级前面)
  40. foreach (var commentDto in comments)
  41. {
  42. var parent = hierarchicalComments.Find(c => c.Comment.Id == commentDto.RepliedCommentId);
  43. if (parent != null)
  44. {
  45. parent.Replies.Add(commentDto);
  46. }
  47. else
  48. {
  49. hierarchicalComments.Add(new CommentWithRepliesDto() { Comment = commentDto });
  50. }
  51. }
  52. hierarchicalComments = hierarchicalComments.OrderByDescending(c => c.Comment.CreationTime).ToList();
  53. #endregion
  54. return hierarchicalComments;
  55. }
  56. public async Task<CommentWithDetailsDto> CreateAsync(CreateCommentDto input)
  57. {
  58. // 也可以使用这种方式(这里只是介绍用法) GuidGenerator.Create()
  59. var comment = new Comment(_guidGenerator.Create(), input.PostId, input.RepliedCommentId, input.Text);
  60. comment = await _commentRepository.InsertAsync(comment);
  61. await CurrentUnitOfWork.SaveChangesAsync();
  62. return ObjectMapper.Map<Comment, CommentWithDetailsDto>(comment);
  63. }
  64. public async Task<CommentWithDetailsDto> UpdateAsync(Guid id, UpdateCommentDto input)
  65. {
  66. var comment = await _commentRepository.GetAsync(id);
  67. comment.SetText(input.Text);
  68. comment = await _commentRepository.UpdateAsync(comment);
  69. return ObjectMapper.Map<Comment, CommentWithDetailsDto>(comment);
  70. }
  71. public async Task DeleteAsync(Guid id)
  72. {
  73. await _commentRepository.DeleteAsync(id);
  74. var replies = await _commentRepository.GetRepliesOfComment(id);
  75. foreach (var reply in replies)
  76. {
  77. await _commentRepository.DeleteAsync(reply.Id);
  78. }
  79. }
  80. private async Task<List<CommentWithDetailsDto>> GetListOfPostAsync(Guid postId)
  81. {
  82. var comments = await _commentRepository.GetListOfPostAsync(postId);
  83. return new List<CommentWithDetailsDto>(
  84. ObjectMapper.Map<List<Comment>, List<CommentWithDetailsDto>>(comments));
  85. }
  86. }

  1. CreateMap<Comment, CommentWithDetailsDto>().Ignore(x => x.Writer);

结语

说明:

  • 1.整个评论的实现非常简单,我们只是实现了一个2层的嵌套。
  • 2.下一章我们讲授权和策略大家应该会比较喜欢,加油

联系作者:加群:867095512 @MrChuJiu

九、Abp vNext 基础篇丨评论聚合功能的更多相关文章

  1. 六、Abp vNext 基础篇丨文章聚合功能上

    介绍 9月开篇讲,前面几章群里已经有几个小伙伴跟着做了一遍了,遇到的问题和疑惑也都在群里反馈和解决好了,9月咱们保持保持更新.争取10月份更新完基础篇. 另外番外篇属于 我在abp群里和日常开发的问题 ...

  2. 七、Abp vNext 基础篇丨文章聚合功能下

    介绍 不好意思这篇文章应该早点更新的,这几天在忙CICD的东西没顾得上,等后面整好了CICD我也发2篇文章讲讲,咱们进入正题,这一章来补全剩下的 2个接口和将文章聚合进行完善. 开工 上一章大部分业务 ...

  3. 八、Abp vNext 基础篇丨标签聚合功能

    介绍 本章节先来把上一章漏掉的上传文件处理下,然后实现Tag功能. 上传文件 上传文件其实不含在任何一个聚合中,它属于一个独立的辅助性功能,先把抽象接口定义一下,在Bcvp.Blog.Core.App ...

  4. 十一、Abp vNext 基础篇丨测试

    前言 祝大家国庆快乐,本来想国庆之前更新完的,结果没写完,今天把剩下的代码补了一下总算ok了. 本章节也是我们后端日常开发中最重要的一步就是测试,我们经常听到的单元测试.集成测试.UI测试.系统测试, ...

  5. 五、Abp vNext 基础篇丨博客聚合功能

    介绍 业务篇章先从客户端开始写,另外补充一下我给项目起名的时候没多想起的太随意了,结果后面有些地方命名冲突了需要通过手动using不过问题不大. 开工 应用层 根据第三章分层架构里面讲到的现在我们模型 ...

  6. Abp vNext 基础篇丨分层架构

    介绍 本章节对 ABP 框架进行一个简单的介绍,摘自ABP官方,后面会在使用过程中对各个知识点进行细致的讲解. 领域驱动设计 领域驱动设计(简称:DDD)是一种针对复杂需求的软件开发方法.将软件实现与 ...

  7. Abp vNext 基础篇丨领域构建

    介绍 我们将通过例⼦介绍和解释⼀些显式规则.在实现领域驱动设计时,应该遵循这些规则并将其应⽤到解决⽅案中. 领域划分 首先我们先对比下Blog.Core和本次重构设计上的偏差,可以看到多了一个博客管理 ...

  8. 十、Abp vNext 基础篇丨权限

    介绍 本章节来把接口的权限加一下 权限配置和使用 官方地址:https://docs.abp.io/en/abp/latest/Authorization 下面这种代码可能我们日常开发都写过,ASP. ...

  9. 初识ABP vNext(11):聚合根、仓储、领域服务、应用服务、Blob存储

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 聚合根 仓储 领域服务 BLOB存储 应用服务 单元测试 模块引用 最后 前言 在前两节中介绍了ABP模块开发的基本步 ...

随机推荐

  1. 得到、微信、美团、爱奇艺APP组件化架构实践

    一.背景 随着项目逐渐扩展,业务功能越来越多,代码量越来越多,开发人员数量也越来越多.此过程中,你是否有过以下烦恼? 项目模块多且复杂,编译一次要5分钟甚至10分钟?太慢不能忍? 改了一行代码 或只调 ...

  2. 跟我一起写 Makefile(七)

    使用变量 ---- 在Makefile中的定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方.其与C/C++所不同的是 ...

  3. Python断言及常用断言函数总结

    Python断言 Python assert 语句,又称断言语句,可以看做是功能缩小版的 if 语句,它用于判断某个表达式的值,如果值为真,则程序可以继续往下执行:反之,Python 解释器会报 As ...

  4. 【笔记】numpy.array基础(3)

    numpy数组的合并与分割 合并操作 concatenate拼接,只能操作维数一样的数据 且并不局限于两个元素 对于二维数组来说,可以通过控制axis来控制是按照行还是按照列来进行拼接操作,默认为ax ...

  5. Windows提权总结

    当以低权用户进去一个陌生的windows机器后,无论是提权还是后续做什么,第一步肯定要尽可能的搜集信息.知己知彼,才百战不殆. 常规信息搜集 systeminfo 查询系统信息 hostname 主机 ...

  6. Redis如何实现分布式锁

    今天我们来聊一聊分布式锁的那些事. 相信大家对锁已经不陌生了,我们在多线程环境中,如果需要对同一个资源进行操作,为了避免数据不一致,我们需要在操作共享资源之前进行加锁操作.在计算机科学中,锁(lock ...

  7. HDFS 09 - HDFS NameNode 的高可用机制

    目录 1 - 为什么要高可用 2 - NameNode 的高可用发展史 3 - HDFS 的高可用架构 3.1 Standby 和 Active 的命名空间保持一致 3.2 同一时刻只有一个 Acti ...

  8. Linux下MySQL主从复制(Binlog)的部署过程

    什么是 MySQL 的主从复制 Mysql内建的复制功能是构建大型高性能应用程序的基础, 将Mysql数据分布到多个系统上,这种分布机制是通过将Mysql某一台主机数据复制到其它主机(slaves)上 ...

  9. 为什么网络损伤仪WANsim中没有流量通过

    在使用网络损伤仪 WANsim 的过程中,有时候发现网损仪中没有流量通过.有些小伙伴可能会想:自己所有配置都是正确的 ,为什么会没有流量通过呢? 有可能,是你忽略了一些东西. 下面,我总结了一些导致网 ...

  10. .net core 微服务参考文章

    网址: https://www.cnblogs.com/edisonchou/p/9124985.html Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.Consul基础介绍 Co ...