I have three tables 'Movie', 'Genre' and it's associated table 'MovieGenre'. What I have to do is to combine the value of Movie table with Genre table and to display the Name value from Genre table with Movie table values, Using the third associated table MovieGenre.
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; }
}
This is the Context page for this
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);
}
I used database-first method. I have created all other part and it is working correctly when I enter values to the table from database. 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.
This is the code in create action method. How can I store the 'MovieId' and 'GenreId' to the 'MovieGenre' table from this code?
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);
}
Below is the create Action view code, here I used check boxes for the Genre, I want to enter the GenreId from this somehow to the associate table too.
<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.
You don't really need MovieId
because it is auto-generated when SaveChanges{Async}
is called, thus is available only after that call.
But you have explicit join entity MovieGenre
with both navigation and explicit FK properties, so you can utilize the navigation property to specify the new Movie
and let EF Core handle the actual FK for you. For the other FK you can just assign the existing Genre
key (Id).
There are two ways to add a new MovieGenre
record in this scenario. Both require creating MovieGenre
instance and filling in the navigation and FK properties:
var movieGenre = new MovieGenre
{
Movie = movies,
GenreId = genreId // ?? - see below
};
Just not sure where GenreId
is coming from here
Create([Bind("MovieId,Title,Description,Storyline,Year,ReleaseDate,Runtime,MovieType, GenreId")] Movie movies
since the Movie
class doesn't have GenreId
property, so you have to figure that out (eventually revisit the DTO/ViewModel used for communication with the controller).
Once you have that, you either add it to the Movie.MovieGenre
collection:
movies.MovieGenre = new List<MovieGenre> { movieGenre };
_context.Add(movies);
or just add it directly to the db context (set):
_context.Add(movies);
_context.Add(movieGenre);
For this particular scenario the explicit join entity helps a lot. If you instead used the EF Core 5.0+ implicit join entity, implementing that operation would require a different approach.
I have found the right code for this. If anyone need the solution here my GitHub repo with the complete code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.