如何将主键值传递给我的 CRUD 函数?
How to just pass in primary key values to my CRUD functions?
这是我的代码:
albums.cshtml
@page
@model Project.Pages.AlbumsModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<h1 class="display-2">Albums</h1>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Album ID, artist ID, Album title</th>
</tr>
</thead>
<tbody>
@foreach (string album in Model.Albums)
{
<tr>
<td>@album</td>
<td><a asp-page="/Albums/Delete" asp-route-id="@album">Delete</a></td>
<td><a asp-page="/Albums/Edit" asp-route-id="@album">Edit title</a></td>
</tr>
}
</tbody>
</table>
</div>
<div class="row">
<p>Enter a title & ArtistID for a new album: </p>
<form method="POST">
<div><input asp-for="Album.Title" /></div>
<div><input asp-for="Album.ArtistId" /></div>
<input type="submit" />
</form>
</div>
albums.cshtml.cs
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Project.Models;
using System;
namespace Project.Pages
{
public class AlbumsModel : PageModel
{
private Chinook db;
public AlbumsModel(Chinook injectedContext)
{
db = injectedContext;
}
public IEnumerable<string> Albums { get; set; }
public void OnGet()
{
ViewData["Title"] = "Chinook Web Site - Albums";
Albums = db.Albums.Select(s => s.AlbumId.ToString() + ". " + s.ArtistId + ". " + s.Title);
}
[BindProperty]
public Album Album { get; set; }
public IActionResult OnPost()
{
if (ModelState.IsValid)
{
db.Albums.Add(Album);
db.SaveChanges();
return RedirectToPage("/albums");
}
return Page();
}
public IActionResult DeleteAlbum(int AlbumId)
{
var album = db.Albums.Find(AlbumId);
if (album == null) return Page();
db.Albums.Remove(album); db.SaveChanges(); return RedirectToPage("/albums");
}
}
}
delete.cshtml
@page "{id?}"
@model Project.Pages.Albums.DeleteModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<p class="text-danger">@Model.ErrorMessage</p>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Album</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Album.Title)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Album.Title)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Album.ArtistId)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Album.ArtistId)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Album.AlbumId)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Album.AlbumId)
</dd>
</dl>
<form method="post">
<input type="submit" value="Delete" asp-route-id="@Model.Album.AlbumId" class="btn btn-danger" /> |
<a asp-page="/Albums">Back to List</a>
</form>
</div>
delete.cshtml.cs
#region snippet_All
using Project.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace Project.Pages.Albums
{
public class DeleteModel : PageModel
{
private readonly Chinook _context;
public DeleteModel(Chinook context)
{
_context = context;
}
[BindProperty]
public Album Album { get; set; }
public string ErrorMessage { get; set; }
public async Task<IActionResult> OnGetAsync(string? id, bool? saveChangesError = false) //changed int -> string
{
if (id == null)
{
return NotFound();
}
//using string.split method to split the id parameter, and get the albumid.
var albumid = System.Convert.ToInt32(id.ToString().Split('.')[0]);
Album = await _context.Albums
.AsNoTracking()
.FirstOrDefaultAsync(m => m.AlbumId == albumid);
if (Album == null)
{
return NotFound();
}
if (saveChangesError.GetValueOrDefault())
{
ErrorMessage = "Delete failed. Try again";
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int? id)
{
if (id == null)
{
return NotFound();
}
var album = await _context.Albums.FindAsync(id);
if (album == null)
{
return NotFound();
}
try
{
_context.Albums.Remove(album);
await _context.SaveChangesAsync();
return RedirectToPage("/Albums");
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
return RedirectToAction("/Albums/Delete",
new { id, saveChangesError = true });
}
}
}
}
#endregion
edit.cshtml
@page
@model Project.Pages.Albums.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Album</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Album.AlbumId" />
<div class="form-group">
<label asp-for="Album.Title" class="control-label"></label>
<input asp-for="Album.Title" class="form-control" />
<span asp-validation-for="Album.Title" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="/Albums">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
edit.cshtml.cs
using Project.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
namespace Project.Pages.Albums
{
public class EditModel : PageModel
{
private readonly Chinook _context;
public EditModel(Chinook context)
{
_context = context;
}
[BindProperty]
public Album Album { get; set; }
public string ErrorMessage { get; set; }
#region snippet_OnGetPost
// public async Task<IActionResult> OnGetAsync(int? id)
// {
// if (id == null)
// {
// return NotFound();
// }
// Album = await _context.Albums.FindAsync(id);
// if (Album == null)
// {
// return NotFound();
// }
// return Page();
// }
public async Task<IActionResult> OnGetAsync(string? id, bool? saveChangesError = false) //changed int -> string
{
if (id == null)
{
return NotFound();
}
//using string.split method to split the id parameter, and get the albumid.
var albumid = System.Convert.ToInt32(id.ToString().Split('.')[0]);
Album = await _context.Albums
.AsNoTracking()
.FirstOrDefaultAsync(m => m.AlbumId == albumid);
if (Album == null)
{
return NotFound();
}
if (saveChangesError.GetValueOrDefault())
{
ErrorMessage = "Delete failed. Try again";
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
var albumToUpdate = await _context.Albums.FindAsync(id);
if (albumToUpdate == null)
{
return NotFound();
}
if (await TryUpdateModelAsync<Album>(
albumToUpdate,
"album",
s => s.Title))
{
await _context.SaveChangesAsync();
return RedirectToPage("/Albums");
}
return Page();
}
#endregion
private bool AlbumExists(int id)
{
return _context.Albums.Any(e => e.AlbumId == id);
}
}
}
我的代码构建和运行正常,但是当我去编辑时,我得到了,例如
This localhost page can’t be found
No web page was found for the web address: https://localhost:5001/Albums/Edit/353.%20123.%20Test
我确定它应该在 AlbumId
中传递,如
https://localhost:5001/Albums/Edit/353
...当我手动将 URL 更改为那个时,它起作用了。
删除功能适用于,例如...
https://localhost:5001/Albums/Delete/353.%20123.%20Test2
...其中“353”是 AlbumId
,“123”是 ArtistId
,'Test2' 是 Title
。
...但这实际上 确实 有效。那么我怎样才能让 AlbumId
中的 Delete 和 Edit 都起作用呢?这就是所有需要的,对吧? TIA 寻求任何帮助。
我认为您的问题在于您 return 从 Album.cshtml.cs 获取信息的方式。而不是构建一个 IEnumerable of strings return 的 IEnumerable of Album
public IEnumerable<Album> Albums { get; set; }
public void OnGetAsync()
{
ViewData["Title"] = "Chinook Web Site - Albums";
Albums = db.Albums;
}
现在,在 Album.cshtml 文件中,您可以使用强类型模型创建每个专辑的列表,其中包含删除和编辑具有正确 ID 的每一行的链接
<thead class="thead-inverse">
<tr>
<th>Album ID</th>
<th>artist ID</th>
<th>Album title</th>
<th></th><th></th>
</tr>
</thead>
<tbody>
@foreach (Album album in Model.Albums)
{
<tr>
<td>@album.AlbumID</td>
<td>@album.ArtistID</td>
<td>@album.Title</td>
<td><a asp-page="/Albums/Delete" asp-route-id="@album.AlbumID">Delete</a></td>
<td><a asp-page="/Albums/Edit" asp-route-id="@album.AlbumID">Edit title</a></td>
</tr>
}
</tbody>
最后,您可以改回编辑和删除代码以接收在 asp-route-id
中传递的整数
public async Task<IActionResult> OnGetAsync(int id, bool? saveChangesError = false)
{
Album = await _context.Albums
.AsNoTracking()
.FirstOrDefaultAsync(m => m.AlbumId == id);
if(Album == null)
.....
}
这是我的代码:
albums.cshtml
@page
@model Project.Pages.AlbumsModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<h1 class="display-2">Albums</h1>
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Album ID, artist ID, Album title</th>
</tr>
</thead>
<tbody>
@foreach (string album in Model.Albums)
{
<tr>
<td>@album</td>
<td><a asp-page="/Albums/Delete" asp-route-id="@album">Delete</a></td>
<td><a asp-page="/Albums/Edit" asp-route-id="@album">Edit title</a></td>
</tr>
}
</tbody>
</table>
</div>
<div class="row">
<p>Enter a title & ArtistID for a new album: </p>
<form method="POST">
<div><input asp-for="Album.Title" /></div>
<div><input asp-for="Album.ArtistId" /></div>
<input type="submit" />
</form>
</div>
albums.cshtml.cs
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Project.Models;
using System;
namespace Project.Pages
{
public class AlbumsModel : PageModel
{
private Chinook db;
public AlbumsModel(Chinook injectedContext)
{
db = injectedContext;
}
public IEnumerable<string> Albums { get; set; }
public void OnGet()
{
ViewData["Title"] = "Chinook Web Site - Albums";
Albums = db.Albums.Select(s => s.AlbumId.ToString() + ". " + s.ArtistId + ". " + s.Title);
}
[BindProperty]
public Album Album { get; set; }
public IActionResult OnPost()
{
if (ModelState.IsValid)
{
db.Albums.Add(Album);
db.SaveChanges();
return RedirectToPage("/albums");
}
return Page();
}
public IActionResult DeleteAlbum(int AlbumId)
{
var album = db.Albums.Find(AlbumId);
if (album == null) return Page();
db.Albums.Remove(album); db.SaveChanges(); return RedirectToPage("/albums");
}
}
}
delete.cshtml
@page "{id?}"
@model Project.Pages.Albums.DeleteModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<p class="text-danger">@Model.ErrorMessage</p>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Album</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Album.Title)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Album.Title)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Album.ArtistId)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Album.ArtistId)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Album.AlbumId)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Album.AlbumId)
</dd>
</dl>
<form method="post">
<input type="submit" value="Delete" asp-route-id="@Model.Album.AlbumId" class="btn btn-danger" /> |
<a asp-page="/Albums">Back to List</a>
</form>
</div>
delete.cshtml.cs
#region snippet_All
using Project.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace Project.Pages.Albums
{
public class DeleteModel : PageModel
{
private readonly Chinook _context;
public DeleteModel(Chinook context)
{
_context = context;
}
[BindProperty]
public Album Album { get; set; }
public string ErrorMessage { get; set; }
public async Task<IActionResult> OnGetAsync(string? id, bool? saveChangesError = false) //changed int -> string
{
if (id == null)
{
return NotFound();
}
//using string.split method to split the id parameter, and get the albumid.
var albumid = System.Convert.ToInt32(id.ToString().Split('.')[0]);
Album = await _context.Albums
.AsNoTracking()
.FirstOrDefaultAsync(m => m.AlbumId == albumid);
if (Album == null)
{
return NotFound();
}
if (saveChangesError.GetValueOrDefault())
{
ErrorMessage = "Delete failed. Try again";
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int? id)
{
if (id == null)
{
return NotFound();
}
var album = await _context.Albums.FindAsync(id);
if (album == null)
{
return NotFound();
}
try
{
_context.Albums.Remove(album);
await _context.SaveChangesAsync();
return RedirectToPage("/Albums");
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
return RedirectToAction("/Albums/Delete",
new { id, saveChangesError = true });
}
}
}
}
#endregion
edit.cshtml
@page
@model Project.Pages.Albums.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Album</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Album.AlbumId" />
<div class="form-group">
<label asp-for="Album.Title" class="control-label"></label>
<input asp-for="Album.Title" class="form-control" />
<span asp-validation-for="Album.Title" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="/Albums">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
edit.cshtml.cs
using Project.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
namespace Project.Pages.Albums
{
public class EditModel : PageModel
{
private readonly Chinook _context;
public EditModel(Chinook context)
{
_context = context;
}
[BindProperty]
public Album Album { get; set; }
public string ErrorMessage { get; set; }
#region snippet_OnGetPost
// public async Task<IActionResult> OnGetAsync(int? id)
// {
// if (id == null)
// {
// return NotFound();
// }
// Album = await _context.Albums.FindAsync(id);
// if (Album == null)
// {
// return NotFound();
// }
// return Page();
// }
public async Task<IActionResult> OnGetAsync(string? id, bool? saveChangesError = false) //changed int -> string
{
if (id == null)
{
return NotFound();
}
//using string.split method to split the id parameter, and get the albumid.
var albumid = System.Convert.ToInt32(id.ToString().Split('.')[0]);
Album = await _context.Albums
.AsNoTracking()
.FirstOrDefaultAsync(m => m.AlbumId == albumid);
if (Album == null)
{
return NotFound();
}
if (saveChangesError.GetValueOrDefault())
{
ErrorMessage = "Delete failed. Try again";
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
var albumToUpdate = await _context.Albums.FindAsync(id);
if (albumToUpdate == null)
{
return NotFound();
}
if (await TryUpdateModelAsync<Album>(
albumToUpdate,
"album",
s => s.Title))
{
await _context.SaveChangesAsync();
return RedirectToPage("/Albums");
}
return Page();
}
#endregion
private bool AlbumExists(int id)
{
return _context.Albums.Any(e => e.AlbumId == id);
}
}
}
我的代码构建和运行正常,但是当我去编辑时,我得到了,例如
This localhost page can’t be found No web page was found for the web address: https://localhost:5001/Albums/Edit/353.%20123.%20Test
我确定它应该在 AlbumId
中传递,如
https://localhost:5001/Albums/Edit/353
...当我手动将 URL 更改为那个时,它起作用了。
删除功能适用于,例如...
https://localhost:5001/Albums/Delete/353.%20123.%20Test2
...其中“353”是 AlbumId
,“123”是 ArtistId
,'Test2' 是 Title
。
...但这实际上 确实 有效。那么我怎样才能让 AlbumId
中的 Delete 和 Edit 都起作用呢?这就是所有需要的,对吧? TIA 寻求任何帮助。
我认为您的问题在于您 return 从 Album.cshtml.cs 获取信息的方式。而不是构建一个 IEnumerable of strings return 的 IEnumerable of Album
public IEnumerable<Album> Albums { get; set; }
public void OnGetAsync()
{
ViewData["Title"] = "Chinook Web Site - Albums";
Albums = db.Albums;
}
现在,在 Album.cshtml 文件中,您可以使用强类型模型创建每个专辑的列表,其中包含删除和编辑具有正确 ID 的每一行的链接
<thead class="thead-inverse">
<tr>
<th>Album ID</th>
<th>artist ID</th>
<th>Album title</th>
<th></th><th></th>
</tr>
</thead>
<tbody>
@foreach (Album album in Model.Albums)
{
<tr>
<td>@album.AlbumID</td>
<td>@album.ArtistID</td>
<td>@album.Title</td>
<td><a asp-page="/Albums/Delete" asp-route-id="@album.AlbumID">Delete</a></td>
<td><a asp-page="/Albums/Edit" asp-route-id="@album.AlbumID">Edit title</a></td>
</tr>
}
</tbody>
最后,您可以改回编辑和删除代码以接收在 asp-route-id
中传递的整数public async Task<IActionResult> OnGetAsync(int id, bool? saveChangesError = false)
{
Album = await _context.Albums
.AsNoTracking()
.FirstOrDefaultAsync(m => m.AlbumId == id);
if(Album == null)
.....
}