![](/img/trans.png)
[英]EF Core 5.0 - Updating many-to-many entities in ASP.NET Core Web API
[英]Adding records to database with many-to-many relations in ASP.NET Core app with EF Core
您好,出於學習目的,我正在為電影數據庫編寫 ASP.NET Core Web API 應用程序,其圖表如下所示:
數據庫圖 img 鏈接(抱歉,沒有足夠的聲譽來發布圖片)
這是 Context 類的樣子
public class MovieDbContext : DbContext
{
public MovieDbContext(DbContextOptions<MovieDbContext> options)
:base(options)
{}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MovieActor>()
.HasKey(ma => new { ma.MovieId, ma.ActorId });
modelBuilder.Entity<MovieGenre>()
.HasKey(mg => new { mg.MovieId, mg.GenreId});
}
public DbSet<Movie> Movies { get; set; }
public DbSet<Actor> Actors { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<MovieActor> MovieActors { get; set; }
public DbSet<MovieGenre> MovieGenres { get; set; }
}
我在一些資源和 stackoverflow 帖子中讀到過,將 DTO 類用於請求是一種很好的做法,因此我為名為MovieCreate
的Movie
實體實現了一個。
public class Movie
{
public int MovieId { get; set; }
[Required]
[StringLength(200)]
public string Name { get; set; }
[Required]
public int Year { get; set; }
[Required]
[StringLength(4000)]
public string Description { get; set; }
[Required]
[Column(TypeName = "decimal(3, 1)")]
public decimal Score { get; set; }
[Required]
[StringLength(2000)]
public string ImgUrl { get; set; }
public IList<MovieActor> MovieActors { get; set; }
public IList<MovieGenre> MovieGenres { get; set; }
}
public class MovieCreate
{
public string Name { get; set; }
public int Year { get; set; }
public string Description { get; set; }
public decimal Score { get; set; }
public string ImgUrl { get; set; }
public IList<int> ActorIds { get; set; }
public IList<int> GenreIds { get; set; }
}
MovieCreate
類和Movie
實體之間的區別在於沒有MovieId
屬性,因為我們不知道 PK 的當前值,更重要的是 IDENTITY_INSERT 參數為 OFF,因此在 DTO 類中沒有意義。 另一個區別是導航屬性的類型更改,例如,由於缺少MovieId
信息而再次從IList<MovieGenre>
更改為IList<int>
。
所以我試圖找出將數據從 POST 請求存儲到數據庫的正確方法。 我在 DataAccess 項目中有一個負責數據庫操作的服務。 該服務中的Create
方法如下所示:
public async Task<MovieResponse> Create(MovieCreate newMovie)
{
Movie movie = newMovie.MapMovie();
//We save changes to database first so that MovieId is assigned to movie variable
_context.Movies.Add(movie);
await _context.SaveChangesAsync();
foreach (var actor in newMovie.ActorIds)
{
movie.MovieActors.Add(new MovieActor { ActorId = actor, MovieId = movie.MovieId });
}
foreach (var genre in newMovie.GenreIds)
{
movie.MovieGenres.Add(new MovieGenre { GenreId = genre, MovieId = movie.MovieId });
}
_context.Movies.Update(movie);
await _context.SaveChangesAsync();
return movie.MapMovieResponse();
}
我想知道這是正確的還是應該說可以接受的做事方式? 同樣通過反復試驗和一些谷歌搜索,我認為通過明確地將MovieId
分配給 0 或從不分配它,這將導致它成為默認整數值(也為 0),EF 會假設我們沒有' 沒有明確指定 PK 值,所以它會在保存時由數據庫生成,所以這樣的代碼也有效:
public async Task<MovieResponse> Create(MovieCreate newMovie)
{
Movie movie = newMovie.MapMovie();
//technically movie.MovieId == 0 at this point, since no value was assigned to it, so it's default
foreach (var actor in newMovie.ActorIds)
{
movie.MovieActors.Add(new MovieActor { ActorId = actor, MovieId = 0});
}
foreach (var genre in newMovie.GenreIds)
{
movie.MovieGenres.Add(new MovieGenre { GenreId = genre, MovieId = 0});
}
//And now we save changes to the database
_context.Movies.Add(movie);
await _context.SaveChangesAsync();
return movie.MapMovieResponse();
}
同樣在Create
方法的第一個版本中,例如,我可以將數據添加到MovieGenres
DbSet
,而不是將MovieGenre
數據添加到導航屬性。 那么哪種方式是“正確”的呢?
PS 如果不是問太多,我真的很感激有關更新(PUT)和 PATCH 請求的任何提示,我認為特別是在 PATCH 上,因為從我在 stackoverflow 上看到的內容來看,它真的很復雜。
這兩個選項顯然都有效,所以我不知道“正確”是否是正確的術語。 但是從代碼和性能的角度來看,第二個選項肯定更有效。 代碼更易於閱讀且更緊湊,並且您只需調用 SaveChanges 一次。 您可以通過刪除連接表的“MovieId = 0”來稍微清理第二個選項。 它由 EF 假定,因此您不需要它。
就個人而言,對於更新,我只是提取現有記錄,然后手動檢查那些可以更新的屬性,進行比較以查看它們是否更改並在需要時更新(一堆 IF 語句)。 通過只接觸實際更新的字段,EF 可以創建更高效的 UPDATE 查詢。 如果不需要,不要只是將每個字段從傳入的更新 DTO 自動復制到現有實體。
很抱歉,我不怎么使用 PATCH,所以我不能談論它。
將 ActorIds 和 GenreIds 更改為 int 數組
public class MovieCreationDto
{
public string Name { get; set; }
public int Year { get; set; }
public string Description { get; set; }
public decimal Score { get; set; }
public string ImgUrl { get; set; }
public int[] ActorIds { get; set; }
public int[] GenreIds { get; set; }
}
並將您的項目更新到 ASP.NET Core 5 和 EF Core 5 因為在 EF Core 5 中建立多對多關系非常容易,而查詢多對多關系要容易得多。
使用 LINQ 中的 Select(Projection) 更改將演員和流派添加到電影的方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.