翼度科技»论坛 编程开发 .net 查看内容

.NET 个人博客-给文章添加上标签

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
个人博客-给文章添加上标签

优化计划


  • 置顶3个且可滚动或切换
  • 推荐改为4个,然后新增历史文章,将推荐的加载更多放入历史文章,按文章发布时间降序排列。
  • 标签功能,可以为文章贴上标签
  • 推荐点赞功能
本篇文章实现文章标签功能
思路

首先需要新增一个标签类Tag,然后Post文章类和Tag标签类的关系是多对多的关系。也就是一个文章可以有多个标签,一个标签也可以被多个文章使用。
为了实现这个多对多关系,光有Tag表和Post表还不够,还需要一个中间表去维护标签和文章之间的关联关系,就定为PostTag表吧。
代码实现

准备工作

为Post类新增导航属性
  1. public List<Tag> Tags { get; set; }
复制代码
新增Tag类
  1. public class Tag
  2. {
  3.     /// <summary>
  4.     /// 标签ID
  5.     /// </summary>
  6.     [Key] //主键
  7.     public int Id { get; set; }
  8.     /// <summary>
  9.     /// 标签名称
  10.     /// </summary>
  11.     public string Name { get; set; }
  12.     /// <summary>
  13.     /// 导航属性 - 文章列表
  14.     /// </summary>
  15.     public List<Post>? Posts { get; set; }
  16. }
复制代码
新增PostTag类
  1. public class PostTag
  2. {
  3.     /// <summary>
  4.     /// 标签ID
  5.     /// </summary>
  6.     public int TagId { get; set; }
  7.     /// <summary>
  8.     /// 导航属性 - 文章
  9.     /// </summary>
  10.     public Post Post { get; set; }
  11.     /// <summary>
  12.     /// 导航属性 - 标签
  13.     /// </summary>
  14.     public Tag Tag { get; set; }
  15. }
复制代码
在DbContext数据库上下文中添加新增类
  1. public DbSet<Tag> Tags { get; set; }
  2. public DbSet<PostTag> PostTags { get; set; }
复制代码
然后是上下文的protected override void OnModelCreating(ModelBuilder modelBuilder)方法中添加
  1. modelBuilder.Entity<Post>()
  2.     .HasMany(e => e.Tags)
  3.     .WithMany(e => e.Posts)
  4.     .UsingEntity<PostTag>();
复制代码
类创建完成后,需要在数据库中新增Tags表和PostTags表,使用Code First模式或者手动创建都行。
控制器

修改之前打包上传文章的控制器,新增List tags
  1. public async Task<ApiResponse<Post>> Upload([FromForm] String Categoryname,[FromForm]String Parent, [FromForm] List<string> tags,IFormFile file,[FromServices] ICategoryService categoryService )
复制代码
服务

在之前的打包上传服务新增标签处理
  1. public async Task<Post> Upload(int CategoryId, List<string> tags,IFormFile file){
  2.     ....之前的代码
  3.          foreach (var tagName in tags)
  4.             {
  5.                 var tag = await _myDbContext.Tags.FirstOrDefaultAsync(t => t.Name == tagName);
  6.                 if (tag == null)
  7.                 {
  8.                     tag = new Tag { Name = tagName };
  9.                     _myDbContext.Tags.Add(tag);
  10.                 }
  11.                 var postTag = new PostTag
  12.                 {
  13.                     Post = post,
  14.                     Tag = tag
  15.                 };
  16.                 _myDbContext.PostTags.Add(postTag);
  17.             }
  18.                 await _myDbContext.SaveChangesAsync();
  19.             return post;
  20. }
复制代码
接口测试


可以看到tags是一个数组类型的参数

数据库也是添加成功了
Razor页面

上述只是简单的在上传文章的时候设置了一下标签,接下来设计一下页面显示
分页查询服务

首先是分页查询服务,可以看到是返回的一个元组,然后PaginationMetadata是分页数据,之前在做推荐博客加载的时候提过一下,之前是没有用到的,然后现在是用到了,所以需要计算一下分页的信息。顺便提一下这个类是大佬的一个Nuget包,然后是提供了ApiResponsePaged类去把元组和数据类结合在一起,在博客的评论中就用到了ApiResponsePaged类来返回数据给前端。但考虑的标签页的设计,就没用这个类,而是直接使用元组,我发现元组用着也不错。
  1.     public async Task<(List<PostTag>, PaginationMetadata)> GetAllTagPostAsync(QueryParameters param)
  2.     {
  3.         var postTags = await _myDbContext.PostTags
  4.             .Where(p => p.TagId == param.TagId)
  5.             .Include(p => p.Post)
  6.             .ThenInclude(p => p.Categories)
  7.             .Include(p => p.Post)
  8.             .ThenInclude(p => p.Comments)
  9.             .Include(p => p.Post)
  10.             .ThenInclude(p => p.Tags)
  11.             .Skip((param.Page - 1) * param.PageSize)
  12.             .Take(param.PageSize)
  13.             .ToListAsync();
  14.    
  15.         var totalCount = await _myDbContext.PostTags.CountAsync(p => p.TagId == param.TagId);
  16.         var pageCount = (int)Math.Ceiling((double)totalCount / param.PageSize);
  17.    
  18.         var pagination = new PaginationMetadata()
  19.         {
  20.             PageNumber = param.Page,
  21.             PageSize = param.PageSize,
  22.             TotalItemCount = totalCount,
  23.             PageCount = pageCount,
  24.             HasPreviousPage = param.Page > 1,
  25.             HasNextPage = param.Page < pageCount,
  26.             IsFirstPage = param.Page == 1,
  27.             IsLastPage = param.Page == pageCount,
  28.             FirstItemOnPage = (param.Page - 1) * param.PageSize + 1,
  29.             LastItemOnPage = Math.Min(param.Page * param.PageSize, totalCount)
  30.         };
  31.    
  32.         return (postTags, pagination);
  33.     }
复制代码
控制器
  1. public async Task<IActionResult> Index(int tagId = 1, int page = 1, int pageSize = 8)
  2.     {
  3.         var TagList = await _tagService.GetAllTagAsync();
  4.         if (TagList.Count == 0)
  5.             return View(new TagIndex()
  6.             {
  7.                 TagList = await _tagService.GetAllTagAsync(),
  8.                 TagId = 0,
  9.                 TagAllPosts = await _tagService.GetAllTagPostAsync(
  10.                     new QueryParameters
  11.                     {
  12.                         Page = page,
  13.                         PageSize = pageSize,
  14.                         TagId = tagId,
  15.                     })
  16.             });
  17.         
  18.         var currentTag = tagId == 1 ? TagList[0] :await _tagService.GetById(tagId);
  19.         if (currentTag == null)
  20.         {
  21.             _messages.Error($"标签 {currentTag} 不存在!");
  22.             return RedirectToAction(nameof(Index));
  23.         }
  24.         TagIndex tagIndex = new TagIndex()
  25.         {
  26.             TagList = await _tagService.GetAllTagAsync(),
  27.             TagId = currentTag.Id,
  28.             TagAllPosts = await _tagService.GetAllTagPostAsync(
  29.                 new QueryParameters
  30.                 {
  31.                     Page = page,
  32.                     PageSize = pageSize,
  33.                     TagId = currentTag.Id,
  34.                 })
  35.         };
  36.         return View(tagIndex);
  37.     }
复制代码
分页组件

[code]@model (Personalblog.Model.ViewModels.Categories.PaginationMetadata,int)    <ul >        <li disabled" : "")">            «                Previous                @for (int i = 1; i

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具