#c# #asp.net #entity-framework #asp.net-core #razor-pages
Вопрос:
Вот мой код:
треки.cshtml
@page
@using Project.Models
@model Project.Pages.TracksModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<h1 class="display-2">Tracks</h1>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Artist name</th>
<th>Album name</th>
<th>Track ID</th>
<th>Track name</th>
</tr>
</thead>
<tbody>
@foreach (Track track in Model.Tracks)
{
<tr>
<td>@Html.DisplayFor(modelArtists => track.Artist.Name)</td>
<td>@Html.DisplayFor(modelAlbums => track.Album.Title)</td>
<td>@track.TrackId</td>
<td>@track.Name</td>
<td><a asp-page="/Tracks/Details" asp-route-id="@track.TrackId">Details</a></td>
<td><a asp-page="/Tracks/Edit" asp-route-id="@track.TrackId">Edit</a></td>
<td><a asp-page="/Tracks/Delete" asp-route-id="@track.TrackId">Delete</a></td>
</tr>
}
</tbody>
</table>
</div>
<div class="row">
<p>Enter a name amp; TrackID (over 3510) for a new track:amp;nbsp;</p>
<form method="POST">
<div><input asp-for="Track.Name" /></div>
<div><input asp-for="Track.TrackId" /></div>
<input type="submit" />
</form>
</div>
<div>
<a asp-page="/Index">Home</a>
</div>
треки.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Project.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Project.Pages
{
public class TracksModel : PageModel
{
private Chinook db;
public TracksModel(Chinook injectedContext)
{
db = injectedContext;
}
public IEnumerable<Track> Tracks { get; set; }
public void OnGetAsync()
{
ViewData["Title"] = "Chinook Web Site - Tracks";
Tracks = db.Tracks.Include(a => a.Album)
.Include(a => a.Artist);
}
[BindProperty]
public Track Track { get; set; }
public IActionResult OnPost()
{
if (ModelState.IsValid)
{
db.Tracks.Add(Track);
db.SaveChanges();
return RedirectToPage("/tracks");
}
return Page();
}
public IActionResult DeleteTrack(int TrackId)
{
var track = db.Tracks.Find(TrackId);
if (track == null) return Page();
db.Tracks.Remove(track); db.SaveChanges(); return RedirectToPage("/tracks");
}
}
}
Что-то не так, так как страница, похоже, повторяет имена исполнителей несколько раз, до такой степени, что все отображаемые имена исполнителей начинаются с буквы A. Я должен сказать, что способ, которым я настроил базу данных, ArtistId
является внешним ключом Album
таблицы, в то время AlbumId
как это внешний ключ Tracks
таблицы.
Может быть, мне нужны такие пункты, как .Where(a => a.AlbumId == Tracks.AlbumId)
и .Where(a => a.ArtistId == Album.ArtistId)
? Я пытался написать что-то подобное, но, должно быть, я сделал это неправильно, так как это просто полностью остановило отображение треков. Какая-нибудь помощь, пожалуйста? ТИА
Правка: Я замечаю, что в то время как названия моих альбомов объединены из Album
таблицы, имена моих исполнителей-нет, хотя метод, по сути, тот же самый. Мне приходит в голову, что, хотя Album
таблица напрямую подключена к Track
таблице (через AlbumId
внешний ключ), Artist
таблица не подключена. Это только косвенно связано с таблицей «Трек», через Album
таблицу».
Artist
—- Album
—- Track
Edit2: Мне сказали, что Where
в данном случае это не нужно, и что я должен использовать «ThenInclude», поэтому в настоящее время у меня есть
public void OnGetAsync()
{
ViewData["Title"] = "Chinook Web Site - Tracks";
Tracks = db.Tracks.Include(a => a.Album).ThenInclude(b => b.Artist).ToList();
}
Однако это все равно приводит к той же самой ошибке.
Комментарии:
1. Возможно, вы могли бы предоставить статический результат html для проверки того, что не так.
2. Извините, я не совсем понимаю, что вы имеете в виду. Но если вы посмотрите на этот скриншот, возможно, вы увидите, что, по-видимому, AC/DC выпускает слишком много релизов. i.imgur.com/fYMZXFL.jpg Это неверно. Имя исполнителя как-то неправильно повторяется.
3. Вы проверили правильность внешнего ключа в базе данных? Потому что, похоже, Aerosmith тоже становится ACDC. Или вы отладили его и проверили, что он работает правильно, прежде чем попасть в цикл?
4. Извините, я не совсем понимаю, что вы имеете в виду? Я могу заставить имена исполнителей нормально отображаться на других страницах моего сайта, только на этой странице у меня возникла эта проблема.
Ответ №1:
Ключевой момент заключается в Context.Chinook.cs
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
....
modelBuilder.Entity<Track>()
.ToTable("tracks")
.HasOne(mtype => mtype.Artist)
.WithMany(trk => trk.Tracks)
.HasForeignKey(mtype => mtype.AlbumId)
.HasForeignKey(mtype => mtype.GenreId)
.HasForeignKey(mtype => mtype.MediaTypeId)
.OnDelete(DeleteBehavior.NoAction);
}
Цепочки HasForeignKey должны быть разделены, если они не связаны с вышеуказанным отношением(1 к n, n к 1, 1 к 1).
Ниже приведены коды, которые я изменил.
Контекст.Chinook.cs
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Album>()
.ToTable("albums")
.HasOne(al => al.Artist)
.WithMany(ar => ar.Albums)
.HasForeignKey(al => al.ArtistId);
modelBuilder.Entity<Artist>().ToTable("artists");
modelBuilder.Entity<Media_type>()
.ToTable("media_types")
.HasKey(c => c.MediaTypeId);
modelBuilder.Entity<Genre>().ToTable("genres");
modelBuilder.Entity<Track>()
.ToTable("tracks")
.HasOne(trk => trk.Album)
.WithMany(trk => trk.Tracks)
.HasForeignKey(trk => trk.AlbumId)
.OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<Track>()
.ToTable("tracks")
.HasOne(trk => trk.Genre)
.WithMany(trk => trk.Tracks)
.HasForeignKey(trk => trk.GenreId);
modelBuilder.Entity<Track>()
.ToTable("tracks")
.HasOne(trk => trk.Media_type)
.WithMany(trk => trk.Tracks)
.HasForeignKey(mtype => mtype.MediaTypeId);
}
Сущности.Художник
public class Artist
{
public int ArtistId { get; set; }
public string Name { get; set; }
public ICollection<Album> Albums { get; set; }
}
Сущности.Жанр
public class Genre
{
public int GenreId { get; set; }
public string Name { get; set; }
public ICollection<Track> Tracks { get; set; }
}
Сущности.Media_type
public class Media_type
{
public int MediaTypeId { get; set; }
public string Name { get; set; }
public ICollection<Track> Tracks { get; set; }
}
Сущности.Дорожка
public class Track
{
public int TrackId { get; set; }
public string Name { get; set; }
public int? AlbumId { get; set; }
public int? MediaTypeId { get; set; }
public int? GenreId { get; set; }
public string Composer { get; set; }
public int? Milliseconds { get; set; }
public int? Bytes { get; set; }
public int? UnitPrice { get; set; }
public Album Album { get; set; }
public Genre Genre { get; set; }
public Media_type Media_type { get; set;}
}
Веб-приложение.треки.cshtml.cs
public void OnGetAsync()
{
ViewData["Title"] = "Chinook Web Site - Tracks";
Tracks = db.Tracks
.Include(a => a.Album)
.ThenInclude(a => a.Artist);
}
WebApp.tracks.cshtml
<tbody>
@foreach (Track track in Model.Tracks)
{
<tr>
<td>@Html.DisplayFor(modelArtists => track.Album.Artist.Name)</td>
<td>@Html.DisplayFor(modelAlbums => track.Album.Title)</td>
<td>@track.TrackId</td>
<td>@track.Name</td>
<td><a asp-page="/Tracks/Details" asp-route-id="@track.TrackId">Details</a></td>
<td><a asp-page="/Tracks/Edit" asp-route-id="@track.TrackId">Edit</a></td>
<td><a asp-page="/Tracks/Delete" asp-route-id="@track.TrackId">Delete</a></td>
</tr>
}
</tbody>