数据存储到 ASP.NET Core 5 MVC 中的关联表

Posted

技术标签:

【中文标题】数据存储到 ASP.NET Core 5 MVC 中的关联表【英文标题】:Data storing to the associated table in ASP.NET Core 5 MVC 【发布时间】:2021-07-24 07:51:36 【问题描述】:

我有三个表“电影”、“流派”,它与表“电影流派”相关联。我要做的是将 Movie 表的值与 Genre 表结合起来,并使用第三个关联表 MovieGenre 显示 Genre 表中的 Name 值和 Movie 表值。

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);

我使用了数据库优先的方法。我已经创建了所有其他部分,当我从数据库向表中输入值时它工作正常。但我想要实现的是在创建新电影时将外键值“MovieId”和“GenreId”存储到“MovieGenre”表中。

这是创建动作方法中的代码。如何通过此代码将“MovieId”和“GenreId”存储到“MovieGenre”表中?

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 输入到关联表中。

<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");

【问题讨论】:

【参考方案1】:

我已经找到了正确的代码。如果有人需要这里的解决方案,请在我的 GitHub 存储库中找到完整的代码。

https://github.com/Iam-Goku/ProjectMovie.git

【讨论】:

【参考方案2】:

但我想要实现的是在创建新电影时将外键值“MovieId”和“GenreId”存储到“MovieGenre”表中。

您实际上并不需要MovieId,因为它是在调用SaveChangesAsync 时自动生成的,因此只有在调用之后才可用。

但是你有明确的连接实体MovieGenrenavigation 和明确的 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 类没有GenreId 属性,因此您必须弄清楚这一点(最终重新访问用于与控制器通信的 DTO/ViewModel)。

一旦你有了它,你可以将它添加到 Movie.MovieGenre 集合中:

movies.MovieGenre = new List<MovieGenre>  movieGenre ;
_context.Add(movies);

或直接将其添加到数据库上下文(集):

_context.Add(movies);
_context.Add(movieGenre);

对于这种特殊情况,显式连接实体有很大帮助。如果您改为使用 EF Core 5.0+ 隐式连接实体,则实现该操作将需要不同的方法。

【讨论】:

很遗憾,asp net 不是我的领域(零经验),我只能回答与 EF Core 相关的问题。

以上是关于数据存储到 ASP.NET Core 5 MVC 中的关联表的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core 5 MVC (.NET 5) 中获取记录的用户数据?

使用存储过程时出现 ASP.Net Core 3.1 MVC 错误

ASP.net core MVC Framework 5 Formdata在附加图像时类型不正确

从 ASP.NET MVC 5 移植到 dotnet core 2:可能替代 System.Web.Mvc.HttpStatusCodeResult [重复]

C# jQuery Ajax 数据表 ASP.NET Core 5 MVC

如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?