You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF与Web API中多对多关系中间表自动填充修复咨询

问题:EF多对多关系中新增电影时中间表未自动写入关联数据

我通过Entity Framework配置了Customer与Movie实体的多对多关系,EF已自动生成包含CustomerId和MovieId双主键的CustomerMovie中间表。但实现AddMovie接口新增电影时,中间表未自动填入添加该电影的CustomerId与对应的MovieId,不确定是接口实现还是关系配置存在问题。

接口实现代码

[HttpPost("AddMovie"), Authorize]
public ActionResult<Movie> AddMovie([FromBody] MovieDto movie)
{
    if (movie == null || !ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    if (_movieRepository.CheckMovieByTitle(movie.Title))
    {
        ModelState.AddModelError("", "Movie Already exists, if both share the same name add the release year with the name");
        return StatusCode(422, ModelState);
    }
    var userEmail = User.FindFirstValue(ClaimTypes.Email);
    Customer customerAdded = _customerRepository.GetCustomerByEmail(userEmail);
    Movie addedMovie = _movieRepository.AddMovie(movie, userEmail, customerAdded);
    
    return Ok(addedMovie);
}

仓储类代码

public Movie AddMovie(MovieDto movie, string email, Customer customerAdded)
{
    Movie newMovie = new Movie
    {
        Title = movie.Title,
        Description = movie.Description,
        Duration = movie.Duration,
        ReleaseDate = movie.ReleaseDate,
        Rating = 0,
        AddedByUser = email
    };

    _context.Movie.Add(newMovie);

    Save();
    return newMovie;
}

DbContext配置代码

public class ClassContextDb : DbContext
{
    public ClassContextDb(DbContextOptions<ClassContextDb> options) : base(options)
    {
    }
    public DbSet<Customer> Customer { get; set; }
    public DbSet<Movie> Movie { get; set; }
    public DbSet<Genre> Genre { get; set; }

    public DbSet<MembershipType> MembershipType { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Customer>()
         .HasMany(c => c.Movie)
         .WithMany(m => m.Customer)
         .UsingEntity(j => j.ToTable("CustomerMovie"));
    }
}

实体模型相关代码

Customer类集合属性

public virtual ICollection<Movie> Movie { get; set; } = new List<Movie>();

Movie类完整代码

public class Movie
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int MovieId { get; set; }

    [Required]
    [MaxLength(30)]
    public string Title { get; set; }

    [Required]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [Range(0, 10)]
    public float Rating { get; set; }

    [Required]
    [MaxLength(200)]
    [MinLength(15)]
    public string Description { get; set; }

    [Required]
    public int Duration { get; set; }
    public string AddedByUser { get; set; }
    public virtual ICollection<Customer> Customer { get; set; } = new List<Customer>();
    public virtual ICollection<Genre> Genre { get; set; }
}

解决方案

核心问题

EF不会自动为新创建的Movie和当前Customer建立关联,必须手动将两者加入对方的关联集合中,EF才会在保存时自动写入中间表数据。

修改仓储类代码

在创建新Movie后,将当前Customer添加到Movie的关联集合,或者将Movie添加到Customer的关联集合,示例如下:

public Movie AddMovie(MovieDto movie, string email, Customer customerAdded)
{
    Movie newMovie = new Movie
    {
        Title = movie.Title,
        Description = movie.Description,
        Duration = movie.Duration,
        ReleaseDate = movie.ReleaseDate,
        Rating = 0,
        AddedByUser = email
    };

    // 建立新电影与当前用户的关联
    newMovie.Customer.Add(customerAdded);
    // 或者反过来:customerAdded.Movie.Add(newMovie);

    _context.Movie.Add(newMovie);
    Save();
    return newMovie;
}

额外注意事项

  1. 确保customerAdded是被EF上下文跟踪的实体:如果GetCustomerByEmail方法是直接从_context.Customer查询返回的,那它默认是被跟踪的;如果是脱离上下文的对象,需要先调用_context.Customer.Attach(customerAdded)将其附加到上下文。
  2. 建议将实体中的集合属性命名为复数形式(比如Movies、Customers),避免与类名混淆,提升代码可读性。

内容的提问来源于stack exchange,提问作者Yazeed Fayoumi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:22:35