EF Core多对多关系中Actor与Director记录重复问题求助
问题:创建电影时重复生成演员/导演记录
问题背景
开发了一个展示电影信息的Web API,包含电影及其关联的演员、导演列表。GET接口能正常返回数据,但POST创建电影时,Actor和Director记录会在SQLite数据库中重复创建。业务规则要求:创建电影必须关联演员和导演,但如果演员或导演已存在于数据库中,则无需重复创建。调用POST接口时,客户端提交的DTO不包含ID,需通过Actor.Name和Director.Name属性匹配查找。
模型类定义
Movie类
public sealed class Movie { public int Id { get; init; } public string Title { get; init; } public string Synopsys { get; init; } public DateOnly ReleaseDate { get; init; } public Genre Genre { get; init; } public ICollection<Actor> Actors { get; init; } public ICollection<Director> Directors { get; init; } }
Actor类
public sealed class Actor { public int Id { get; init; } public string Name { get; init; } public DateOnly DateOfBirth { get; init; } public string Info { get; set; } public ICollection<Movie> Movies { get; set; } }
Director类
public sealed class Director { public int Id { get; init; } public string Name { get; init; } public DateOnly DateOfBirth { get; init; } public string Info { get; init; } public ICollection<Movie> Movies { get; init; } }
ApplicationDBContext配置
定义DbSet和EF Core多对多关系,会生成Movies、Actors、Directors表以及关联表MovieActors和MovieDirectors:
public class ApplicationDBContext : DbContext { public ApplicationDBContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { } public DbSet<Movie> Movies { get; set; } public DbSet<Actor> Actors { get; set; } public DbSet<Director> Directors { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Movie>() .HasMany(a => a.Actors) .WithMany(m => m.Movies) .UsingEntity(am => am.ToTable("MovieActors")); modelBuilder.Entity<Movie>() .HasMany(d => d.Directors) .WithMany(m => m.Movies) .UsingEntity(md => md.ToTable("MovieDirectors")); } }
原仓储CreateAsync方法
最初的仓储方法会跟踪整个Movie对象并插入所有数据,导致重复创建演员/导演:
public class MovieRepository(ApplicationDBContext context) : IMovieRepository { private readonly ApplicationDBContext context = context; public async Task<Movie> CreateAsync(Movie movie) { context.Movies.Add(movie); await context.SaveChangesAsync(); return movie; } }
API控制器代码
[Route("api/[controller]")] [ApiController] // 使用主构造函数 public class MoviesController(IMovieRepository movieRepo) : ControllerBase { private readonly IMovieRepository movieRepo = movieRepo; [HttpPost] public async Task<IActionResult> CreateMovie([FromBody] CreateMovieDto createMovieDto) { var movieModel = createMovieDto.ToMovieFromCreateMovieDto(); if (await movieRepo.Exists(movieModel.Title)) { return BadRequest("该电影已存在"); } var movie = await movieRepo.CreateAsync(movieModel); return CreatedAtAction(nameof(GetMovieById), new { id = movie.Id }, movie.ToMovieDto()); } }
尝试的修改(编辑内容)
尝试修改了CreateAsync方法,先检查数据库中是否存在同名演员/导演,存在则使用已有实体,不存在则添加新实体:
public async Task<Movie> CreateAsync(Movie movie) { var actorsInMovie = movie.Actors; movie.Actors = new List<Actor>(); foreach (var actor in actorsInMovie) { var actorEntity = await context.Actors.FirstOrDefaultAsync(a => a.Name == actor.Name); if (actorEntity is not null) movie.Actors.Add(actorEntity); else movie.Actors.Add(actor); } var directorsInMovie = movie.Directors; movie.Directors = new List<Director>(); foreach (var director in directorsInMovie) { var directorEntity = await context.Directors.FirstOrDefaultAsync(d => d.Name == director.Name); if (directorEntity is not null) movie.Directors.Add(directorEntity); else movie.Directors.Add(director); } await context.Movies.AddAsync(movie); await context.SaveChangesAsync(); return movie; }
内容的提问来源于stack exchange,提问作者Carlos
相关产品推荐
相关产品推荐

