数据存储到 ASP.NET Core 5 MVC 中关联的 table
Data storing to the associated table in ASP.NET Core 5 MVC
我有三个 table 'Movie'、'Genre' 并且它们关联 table 'MovieGenre'。我要做的是将 Movie table 的值与 Genre table 的值结合起来,并显示 Genre table 的 Name 值与 Movie table 的值,使用第三个关联table 电影类型。
public partial class Movie
{
public int MovieId { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
public string Storyline { get; set; }
public int? Year { get; set; }
[DataType(DataType.Date)]
[Validators(ErrorMessage = "Date must be after or equal to current date")]
[Display(Name = "Release Date")]
public DateTime? ReleaseDate { get; set; }
public int? Runtime { get; set; }
[Display(Name = "Movie Type")]
[Column(TypeName = "nvarchar(20)")]
public MovieType MovieType { get; set; }
public ICollection<Genre> Genres { get; set; }
}
public class Genre
{
[Key]
public int GenreId { get; set; }
[Display(Name="Genre name")]
public string Name { get; set; }
public ICollection<Movie> Movies { get; set; }
}
public class MovieGenre
{
public int MovieGenreId { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
public int GenreId { get; set; }
public Genre Genre { get; set; }
}
这是此内容的上下文页面
public partial class MovieContext : DbContext
{
public MovieContext(DbContextOptions<MovieContext> options)
: base(options)
{
}
public virtual DbSet<Movie> Movies { get; set; }
public virtual DbSet<Genre> Genre { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");
modelBuilder.Entity<MovieGenre>().HasKey(mg => new { mg.MovieId, mg.GenreId });
modelBuilder.Entity<Movie>()
.HasMany(p => p.Genres)
.WithMany(p => p.Movies)
.UsingEntity(j => j.ToTable("MovieGenre"));
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
我使用了数据库优先的方法。我已经创建了所有其他部分,当我从数据库向 table 输入值时它工作正常。但是我想要实现的是在创建新电影时将外键值 'MovieId' 和 'GenreId' 存储到 'MovieGenre' table.
这是创建操作方法中的代码。如何将 'MovieId' 和 'GenreId' 存储到此代码中的 'MovieGenre' table?
public async Task<IActionResult> Create([Bind("Title,Description,Storyline,Year,ReleaseDate,Runtime,MovieType")] Movie movies)
{
if (ModelState.IsValid)
{
_context.Add(movies);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewBag.GenreId = new MultiSelectList(_context.Genre.ToList(), "GenreId", "Name");
return View(movies);
}
下面是创建 Action 视图代码,这里我使用了 Genre 的复选框,我也想以某种方式将 GenreId 从这里输入到关联 table。
<div class="row">
<div class="col-md-4 center">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Storyline" class="control-label"></label>
<input asp-for="Storyline" class="form-control" />
<span asp-validation-for="Storyline" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Year" class="control-label"></label>
<input asp-for="Year" class="form-control" />
<span asp-validation-for="Year" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Runtime" class="control-label"></label>
<input asp-for="Runtime" class="form-control" />
<span asp-validation-for="Runtime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieType" class="control-label"></label>
<select asp-for="MovieType" class="form-control" asp-items="Html.GetEnumSelectList<MovieType>()"></select>
<span asp-validation-for="MovieType" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">Movie Genre</label>
<div class="col-md-10">
<div class="checkbox">
@foreach (var item in (MultiSelectList)ViewBag.GenreId)
{
<input type="checkbox" value="@item.Value" id="GenreId" name="GenreId" />@item.Text
}
</div>
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
<a class="btn btn-primary" asp-action="Index">Back to List</a>
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
But what I want to achieve is to store the foreign key values 'MovieId' and 'GenreId' to the 'MovieGenre' table when creating a new movie.
你真的不需要 MovieId
因为它是在调用 SaveChanges{Async}
时自动生成的,因此只有在调用之后才可用。
但是您有显式连接实体 MovieGenre
,同时具有 navigation 和显式 FK 属性,因此您可以使用导航属性 指定新的 Movie
并让 EF Core 为您处理实际的 FK。对于其他 FK,您只需分配 existing Genre
键 (Id)。
在这种情况下,有两种方法可以添加新的 MovieGenre
记录。两者都需要创建 MovieGenre
实例并填写导航和 FK 属性:
var movieGenre = new MovieGenre
{
Movie = movies,
GenreId = genreId // ?? - see below
};
只是不确定 GenreId
来自这里
Create([Bind("MovieId,Title,Description,Storyline,Year,ReleaseDate,Runtime,MovieType, GenreId")] Movie movies
因为 Movie
class 没有 GenreId
属性,所以你必须弄清楚(最终重新访问 DTO/ViewModel 用于与控制器通信)。
一旦你有了它,你要么将它添加到 Movie.MovieGenre
集合:
movies.MovieGenre = new List<MovieGenre> { movieGenre };
_context.Add(movies);
或者直接将其添加到数据库上下文(设置)中:
_context.Add(movies);
_context.Add(movieGenre);
对于这种特殊情况,显式连接实体很有帮助。如果您改为使用 EF Core 5.0+ 隐式连接实体,则实现该操作将需要不同的方法。
我找到了正确的代码。如果有人需要这里的解决方案,我的 GitHub 带有完整代码的 repo。
我有三个 table 'Movie'、'Genre' 并且它们关联 table 'MovieGenre'。我要做的是将 Movie table 的值与 Genre table 的值结合起来,并显示 Genre table 的 Name 值与 Movie table 的值,使用第三个关联table 电影类型。
public partial class Movie
{
public int MovieId { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
public string Storyline { get; set; }
public int? Year { get; set; }
[DataType(DataType.Date)]
[Validators(ErrorMessage = "Date must be after or equal to current date")]
[Display(Name = "Release Date")]
public DateTime? ReleaseDate { get; set; }
public int? Runtime { get; set; }
[Display(Name = "Movie Type")]
[Column(TypeName = "nvarchar(20)")]
public MovieType MovieType { get; set; }
public ICollection<Genre> Genres { get; set; }
}
public class Genre
{
[Key]
public int GenreId { get; set; }
[Display(Name="Genre name")]
public string Name { get; set; }
public ICollection<Movie> Movies { get; set; }
}
public class MovieGenre
{
public int MovieGenreId { get; set; }
public int MovieId { get; set; }
public Movie Movie { get; set; }
public int GenreId { get; set; }
public Genre Genre { get; set; }
}
这是此内容的上下文页面
public partial class MovieContext : DbContext
{
public MovieContext(DbContextOptions<MovieContext> options)
: base(options)
{
}
public virtual DbSet<Movie> Movies { get; set; }
public virtual DbSet<Genre> Genre { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");
modelBuilder.Entity<MovieGenre>().HasKey(mg => new { mg.MovieId, mg.GenreId });
modelBuilder.Entity<Movie>()
.HasMany(p => p.Genres)
.WithMany(p => p.Movies)
.UsingEntity(j => j.ToTable("MovieGenre"));
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
我使用了数据库优先的方法。我已经创建了所有其他部分,当我从数据库向 table 输入值时它工作正常。但是我想要实现的是在创建新电影时将外键值 'MovieId' 和 'GenreId' 存储到 'MovieGenre' table.
这是创建操作方法中的代码。如何将 'MovieId' 和 'GenreId' 存储到此代码中的 'MovieGenre' table?
public async Task<IActionResult> Create([Bind("Title,Description,Storyline,Year,ReleaseDate,Runtime,MovieType")] Movie movies)
{
if (ModelState.IsValid)
{
_context.Add(movies);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewBag.GenreId = new MultiSelectList(_context.Genre.ToList(), "GenreId", "Name");
return View(movies);
}
下面是创建 Action 视图代码,这里我使用了 Genre 的复选框,我也想以某种方式将 GenreId 从这里输入到关联 table。
<div class="row">
<div class="col-md-4 center">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Storyline" class="control-label"></label>
<input asp-for="Storyline" class="form-control" />
<span asp-validation-for="Storyline" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Year" class="control-label"></label>
<input asp-for="Year" class="form-control" />
<span asp-validation-for="Year" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Runtime" class="control-label"></label>
<input asp-for="Runtime" class="form-control" />
<span asp-validation-for="Runtime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MovieType" class="control-label"></label>
<select asp-for="MovieType" class="form-control" asp-items="Html.GetEnumSelectList<MovieType>()"></select>
<span asp-validation-for="MovieType" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">Movie Genre</label>
<div class="col-md-10">
<div class="checkbox">
@foreach (var item in (MultiSelectList)ViewBag.GenreId)
{
<input type="checkbox" value="@item.Value" id="GenreId" name="GenreId" />@item.Text
}
</div>
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
<a class="btn btn-primary" asp-action="Index">Back to List</a>
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
But what I want to achieve is to store the foreign key values 'MovieId' and 'GenreId' to the 'MovieGenre' table when creating a new movie.
你真的不需要 MovieId
因为它是在调用 SaveChanges{Async}
时自动生成的,因此只有在调用之后才可用。
但是您有显式连接实体 MovieGenre
,同时具有 navigation 和显式 FK 属性,因此您可以使用导航属性 指定新的 Movie
并让 EF Core 为您处理实际的 FK。对于其他 FK,您只需分配 existing Genre
键 (Id)。
在这种情况下,有两种方法可以添加新的 MovieGenre
记录。两者都需要创建 MovieGenre
实例并填写导航和 FK 属性:
var movieGenre = new MovieGenre
{
Movie = movies,
GenreId = genreId // ?? - see below
};
只是不确定 GenreId
来自这里
Create([Bind("MovieId,Title,Description,Storyline,Year,ReleaseDate,Runtime,MovieType, GenreId")] Movie movies
因为 Movie
class 没有 GenreId
属性,所以你必须弄清楚(最终重新访问 DTO/ViewModel 用于与控制器通信)。
一旦你有了它,你要么将它添加到 Movie.MovieGenre
集合:
movies.MovieGenre = new List<MovieGenre> { movieGenre };
_context.Add(movies);
或者直接将其添加到数据库上下文(设置)中:
_context.Add(movies);
_context.Add(movieGenre);
对于这种特殊情况,显式连接实体很有帮助。如果您改为使用 EF Core 5.0+ 隐式连接实体,则实现该操作将需要不同的方法。
我找到了正确的代码。如果有人需要这里的解决方案,我的 GitHub 带有完整代码的 repo。