西瓜梨 发表于 2023-8-21 23:14:27

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

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

优化计划


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

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

准备工作

为Post类新增导航属性
public List<Tag> Tags { get; set; }新增Tag类
public class Tag
{
    /// <summary>
    /// 标签ID
    /// </summary>
    //主键
    public int Id { get; set; }

    /// <summary>
    /// 标签名称
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 导航属性 - 文章列表
    /// </summary>
    public List<Post>? Posts { get; set; }
}新增PostTag类
public class PostTag
{
    /// <summary>
    /// 标签ID
    /// </summary>
    public int TagId { get; set; }

    /// <summary>
    /// 导航属性 - 文章
    /// </summary>
    public Post Post { get; set; }

    /// <summary>
    /// 导航属性 - 标签
    /// </summary>
    public Tag Tag { get; set; }
}在DbContext数据库上下文中添加新增类
public DbSet<Tag> Tags { get; set; }
public DbSet<PostTag> PostTags { get; set; }然后是上下文的protected override void OnModelCreating(ModelBuilder modelBuilder)方法中添加
modelBuilder.Entity<Post>()
    .HasMany(e => e.Tags)
    .WithMany(e => e.Posts)
    .UsingEntity<PostTag>();类创建完成后,需要在数据库中新增Tags表和PostTags表,使用Code First模式或者手动创建都行。
控制器

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

在之前的打包上传服务新增标签处理
public async Task<Post> Upload(int CategoryId, List<string> tags,IFormFile file){
    ....之前的代码
         foreach (var tagName in tags)
            {
                var tag = await _myDbContext.Tags.FirstOrDefaultAsync(t => t.Name == tagName);
                if (tag == null)
                {
                  tag = new Tag { Name = tagName };
                  _myDbContext.Tags.Add(tag);
                }

                var postTag = new PostTag
                {
                  Post = post,
                  Tag = tag
                };

                _myDbContext.PostTags.Add(postTag);
            }
                await _myDbContext.SaveChangesAsync();
            return post;
}接口测试


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

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

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

首先是分页查询服务,可以看到是返回的一个元组,然后PaginationMetadata是分页数据,之前在做推荐博客加载的时候提过一下,之前是没有用到的,然后现在是用到了,所以需要计算一下分页的信息。顺便提一下这个类是大佬的一个Nuget包,然后是提供了ApiResponsePaged类去把元组和数据类结合在一起,在博客的评论中就用到了ApiResponsePaged类来返回数据给前端。但考虑的标签页的设计,就没用这个类,而是直接使用元组,我发现元组用着也不错。
    public async Task<(List<PostTag>, PaginationMetadata)> GetAllTagPostAsync(QueryParameters param)
    {
      var postTags = await _myDbContext.PostTags
            .Where(p => p.TagId == param.TagId)
            .Include(p => p.Post)
            .ThenInclude(p => p.Categories)
            .Include(p => p.Post)
            .ThenInclude(p => p.Comments)
            .Include(p => p.Post)
            .ThenInclude(p => p.Tags)
            .Skip((param.Page - 1) * param.PageSize)
            .Take(param.PageSize)
            .ToListAsync();
   
      var totalCount = await _myDbContext.PostTags.CountAsync(p => p.TagId == param.TagId);
      var pageCount = (int)Math.Ceiling((double)totalCount / param.PageSize);
   
      var pagination = new PaginationMetadata()
      {
            PageNumber = param.Page,
            PageSize = param.PageSize,
            TotalItemCount = totalCount,
            PageCount = pageCount,
            HasPreviousPage = param.Page > 1,
            HasNextPage = param.Page < pageCount,
            IsFirstPage = param.Page == 1,
            IsLastPage = param.Page == pageCount,
            FirstItemOnPage = (param.Page - 1) * param.PageSize + 1,
            LastItemOnPage = Math.Min(param.Page * param.PageSize, totalCount)
      };
   
      return (postTags, pagination);
    }控制器

public async Task<IActionResult> Index(int tagId = 1, int page = 1, int pageSize = 8)
    {
      var TagList = await _tagService.GetAllTagAsync();
      if (TagList.Count == 0)
            return View(new TagIndex()
            {
                TagList = await _tagService.GetAllTagAsync(),
                TagId = 0,
                TagAllPosts = await _tagService.GetAllTagPostAsync(
                  new QueryParameters
                  {
                        Page = page,
                        PageSize = pageSize,
                        TagId = tagId,
                  })
            });
      
      var currentTag = tagId == 1 ? TagList :await _tagService.GetById(tagId);
      if (currentTag == null)
      {
            _messages.Error($"标签 {currentTag} 不存在!");
            return RedirectToAction(nameof(Index));
      }

      TagIndex tagIndex = new TagIndex()
      {
            TagList = await _tagService.GetAllTagAsync(),
            TagId = currentTag.Id,
            TagAllPosts = await _tagService.GetAllTagPostAsync(
                new QueryParameters
                {
                  Page = page,
                  PageSize = pageSize,
                  TagId = currentTag.Id,
                })
      };
      return View(tagIndex);
    }分页组件

@model (Personalblog.Model.ViewModels.Categories.PaginationMetadata,int)    <ul >      <li disabled" : "")">            «                Previous                @for (int i = 1; i
页: [1]
查看完整版本: .NET 个人博客-给文章添加上标签