Here is my code:
Tracks.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");
}
}
}
Tracks.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 & TrackID for a new track: </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>
AlbumTracks.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 AlbumTracksModel : PageModel
{
private Chinook db;
public AlbumTracksModel(Chinook injectedContext)
{
db = injectedContext;
}
public IEnumerable<Track> Tracks { get; set; }
public void OnGetAsync(int id)
{
ViewData["Title"] = "Chinook Web Site - Tracks";
Tracks = db.Tracks.Include(a => a.Album).Where(a => a.AlbumId == id);
}
[BindProperty]
public Track Track { get; set; }
public IActionResult OnPost(int id)
{
if (ModelState.IsValid)
{
db.Tracks.Add(Track);
db.SaveChanges();
return RedirectToPage("/Albums/AlbumTracks?id=" + id);
}
return Page();
}
public IActionResult DeleteTrack(int TrackId, int id)
{
var track = db.Tracks.Find(TrackId);
if (track == null) return Page();
db.Tracks.Remove(track);
db.SaveChanges();
return RedirectToPage("/Albums/AlbumTracks?id=" + id);
}
}
}
AlbumTracks.cshtml
@page
@using Project.Models
@model Project.Pages.AlbumTracksModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<h1 class="display-2">Tracks</h1>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Track ID</th>
<th>Track name</th>
</tr>
</thead>
<tbody>
@foreach (Track track in Model.Tracks)
{
<tr>
<td>@track.TrackId</td>
<td>@track.Name</td>
</tr>
}
</tbody>
</table>
</div>
<div class="row">
<p>Enter a name & ID for a new track: </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>
I should explain that ArtistId
is a foreign key of the Albums
table, and AlbumId
is a foreign key of the Tracks
table.
The artist data is coming through to /Tracks
, but there's something wrong, as all of the output are artists beginning with the letter A. So it seems like each artist name is being repeated many more times than it should?
There is another problem with my code, as I noticed that when I try to add a track from the /AlbumTracks
page I have also created, that I get a 'page not found' error for the redirect page, even though the URL appears to be valid. The tracks are added though.
Thanks in advance for any pointers.
Edit: I've decided to forget about adding a track from /Tracks
. I think it makes a lot more sense to just add them from /AlbumTracks
instead.
Edit2: the redirection issue is sorted now. I needed to do
return RedirectToPage("/Albums/AlbumTracks", new {id = id });
So now I need to able to add tracks as part of albums next.
Edit3: I've actually got it working like this:
<div><input asp-for="Track.Name" /></div>
<div><input asp-for="Track.TrackId" /></div>
<div><input asp-for="Track.AlbumId" /></div>
It's just obviously not ideal to make the user manually enter the AlbumId
of the Album they want to add a track to. It would be better to have the system take the AlbumId
directly from the URL, as in
https://localhost:5001/Albums/AlbumTracks?id=361
The first way:
When you get into the Albums/AlbumTracks?id=361
page, you could see the tracks list which AlbumId
equals to 361. If you post the form in this page, the request url is still Albums/AlbumTracks?id=361
. So the id
you get in post handler is the AlbumId
you want. Change your AlbumTracks.cshtml.cs like below:
public class AlbumTracksModel : PageModel
{
//...
public IEnumerable<Track> Tracks { get; set; }
[BindProperty]
public Track Track { get; set; }
public IActionResult OnPost(int id)
{
Track.AlbumId = id; //set the albumid by the request url...
if (ModelState.IsValid)
{
db.Tracks.Add(Track);
db.SaveChanges();
return RedirectToPage("/Albums/AlbumTracks", new { id = id });
}
return RedirectToPage("/Albums/AlbumTracks", new { id = id });
}
Another way is that you could set an input with the AlbumId
when the page load. The AlbumTracks.cshtml
rendered the Tracks for specific AlbumId
and they all own the same AlbumId
. You could just read the AlbumId
like below in AlbumTracks.cshtml:
@page
@using Project.Models
@model Project.Pages.AlbumTracksModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<h1 class="display-2">Tracks</h1>
<table class="table">
//....
</table>
</div>
<div class="row">
<p>Enter a name & TrackID for a new track: </p>
<form method="POST">
<div><input asp-for="Track.Name" /></div>
<div><input asp-for="Track.TrackId" /></div>
//add this....
<div><input asp-for="Tracks.ElementAt(0).AlbumId" name="Track.AlbumId" /></div>
<input type="submit" />
</form>
</div>
Both of the two ways you could get the AlbumId
.