文章目录
- 项目地址
- 一、给Habit添加Tags
- 1.1 创建Tags
- 1. 创建一个新的HabitTags实体
- 2. 设置Habit和Tags的关系
- 3. 设置HabitTag表
- 4. 在HabitConfiguration里配置
- 5. 将表添加到EFCore里
- 6. 迁移数据
- 1.2 给Habit增加/修改标签
- 1. 创建UpsertHabitTagsDto
- 2. 创建查询HabitWithTagsDto
- 3. 创建HabitTagsController
- 1.3 使用Fluent API验证Create tag逻辑
项目地址
- 教程作者:
- 教程地址:
- 代码仓库地址:
- 所用到的框架和插件:
dbt
airflow
一、给Habit添加Tags
1.1 创建Tags
1. 创建一个新的HabitTags实体
- 该实体需要创建一个表,关联Habits和Tags
namespace DevHabit.Api.Entities;public sealed class HabitTag
{public string HabitId { get; set; }public string TagId { get; set; }public DateTime CreatedAtUtc { get; set; }
}
2. 设置Habit和Tags的关系
- 在Habit 的是实体里创建关系
3. 设置HabitTag表
- 添加
HabitTagConfiguration.cs
配置文件
注意:这里Tag的WithMany()是空的
原因是,暂时我们业务上不考虑通过Tag来找所有的Habits; 但是,Habit里面,我们建立了多对多关系,需要通过habit来找到所有的Tag
4. 在HabitConfiguration里配置
- 修改了Habit的实体,我们需要在HabitConfiguration里配置关系
5. 将表添加到EFCore里
ApplicationDbContext.cs
里,添加新的表
public sealed class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : DbContext(options)
{public DbSet<Habit> Habits { get; set; }public DbSet<Tag> Tags { get; set; }public DbSet<HabitTag> HabitTags { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.HasDefaultSchema(Schemas.Application);modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);}
}
6. 迁移数据
- 在Api的Console里先输入
add-migration add HabitTag
- 换到docker环境,运行程序,自动执行
1.2 给Habit增加/修改标签
1. 创建UpsertHabitTagsDto
- 创建UpsertHabitTagsDto,用于处理前端传来的api数据
namespace DevHabit.Api.DTOs.HabitTags;public sealed record UpsertHabitTagsDto
{public required List<string> TagIds { get; init; }
}
2. 创建查询HabitWithTagsDto
- 用于查询单个habit后,显示该habit里的Tags
public sealed record HabitWithTagsDto
{public required string Id { get; init; }public required string Name { get; init; }public string? Description { get; init; }public required HabitType Type { get; init; }public required FrequencyDto Frequency { get; init; }public required TargetDto Target { get; init; }public required HabitStatus Status { get; init; }public required bool IsArchived { get; init; }public DateOnly? EndDate { get; init; }public MilestoneDto? Milestone { get; init; }public required DateTime CreatedAtUtc { get; init; }public DateTime? UpdatedAtUtc { get; init; }public DateTime? LastCompletedAtUtc { get; init; }public required string[] Tags { get; init; }
}
3. 创建HabitTagsController
- 该Controller用于给Habit 处理标签
[HttpPut]public async Task<ActionResult> UpsertHabitTags(string habitId, UpsertHabitTagsDto upsertHabitTagsDto){Habit? habit = await dbContext.Habits.Include(h => h.HabitTags).FirstOrDefaultAsync(h => h.Id == habitId);if (habit is null){return NotFound();}var currentTagIds = habit.HabitTags.Select(ht => ht.TagId).ToHashSet();if (currentTagIds.SetEquals(upsertHabitTagsDto.TagIds)){return NoContent();}List<string> existingTagIds = await dbContext.Tags.Where(t => upsertHabitTagsDto.TagIds.Contains(t.Id)).Select(t => t.Id).ToListAsync();if (existingTagIds.Count != upsertHabitTagsDto.TagIds.Count){return BadRequest("One or more tag IDs is invalid");}habit.HabitTags.RemoveAll(ht => !upsertHabitTagsDto.TagIds.Contains(ht.TagId));string[] tagIdsToAdd = upsertHabitTagsDto.TagIds.Except(currentTagIds).ToArray();habit.HabitTags.AddRange(tagIdsToAdd.Select(tagId => new HabitTag{HabitId = habitId,TagId = tagId,CreatedAtUtc = DateTime.UtcNow}));await dbContext.SaveChangesAsync();return NoContent();}
代码解释:
- 发起
http://localhost:5000/habits/h_0195e900-3c05-7ee6-8b26-7ec6b367d66a/tags
请求 - 接收一个
habitId
以及 UpsertHabitTagsDto
- 根据Id从数据库查询该habit的数据
- 查看是否有新增或者取消:通过数据库tags所有Id的hashSet和前端传来的进行对比,如果没有变化,则返回204
5. 排除非法habitId:查询Tags表的tagId和前端传来的Id进行对比,如果有不一样的,则报错
6. 删除Dto里取出的Tag,保存新增的Tags 完成upsert
7. 发送请求更改Tag