首页 > 解决方案 > 如何将主键值传递给我的 CRUD 函数?

问题描述

这是我的代码:

专辑.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:&nbsp;</p>
    <form method="POST">
        <div><input asp-for="Album.Title" /></div>
        <div><input asp-for="Album.ArtistId" /></div>
        <input type="submit" />
    </form>
</div>

专辑.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");
        }
    }
}

删除.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>

删除.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

编辑.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");}
}

编辑.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);
        }
    }
}

我的代码构建并运行正常,但是当我去编辑时,我得到了,例如

找不到此本地主机页面 没有找到该网址的网页:https://localhost:5001/Albums/Edit/353.%20123.%20Test

我确定它应该只是传递AlbumId,如

https://localhost:5001/Albums/Edit/353

...当我手动将 URL 更改为该 URL 时,它可以工作。

例如,删除功能适用于...

https://localhost:5001/Albums/Delete/353.%20123.%20Test2

...其中“353”是AlbumId,“123”是ArtistId,“Test2”是Title

...但这确实有效。那么我怎样才能让 Delete 和 Edit 都能从AlbumId? 这就是所需要的,对吧?TIA 寻求帮助。

标签: c#asp.netasp.net-corecrudrazor-pages

解决方案


在我看来,您的问题在于您从 Album.cshtml.cs 返回信息的方式。而不是构建一个字符串的 IEnumerable,而是返回专辑的 IEnumerable

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)
    .....
}

推荐阅读