【问题标题】:How to just pass in primary key values to my CRUD functions?如何将主键值传递给我的 CRUD 函数?
【发布时间】:2021-05-10 12:07:13
【问题描述】:

这是我的代码:

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:&nbsp;</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");
        }
    }
}

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

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

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

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

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

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

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

delete 函数的工作原理例如...

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

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

...但实际上 确实 工作。那么我怎样才能让删除和编辑都从AlbumId 工作呢?这就是所需要的,对吧? TIA 寻求帮助。

【问题讨论】:

  • 通常参数在 URL 中问号后,用 & 分隔。见维基:en.wikipedia.org/wiki/Query_string?force_isolation=true
  • asp-route-id="@album"> 应该是 asp-route-id="@album.AlbumID"> 并且,当然,您应该将 Edit.cshtml.cs 中的 OnGetAsync 改回接收整数
  • @jdweng - 不,不是这样,DeleteEdit 的 URL 就像 localhost:5001/Albums/Edit/353.%20123.%20Test
  • @Steve - 我试过了,但我得到 "Pages\albums.cshtml(18,75): error CS1061: 'string' does not contain a definition for 'AlbumID' and no access extension method可以找到接受“字符串”类型的第一个参数的“AlbumID””编辑:我现在正在尝试处理 OnGetAsync 建议,谢谢。
  • 为什么要从 Select 中构建一个 IEnumerable 字符串?这是你问题的根源。返回一个专辑的 IEnumerable 并为您要显示的每个元素构建一个列,然后您可以使用 @album.AlbumID

标签: c# asp.net asp.net-core crud razor-pages


【解决方案1】:

在我看来,您的问题在于您从 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)
    .....
}

【讨论】:

  • 谢谢,我正在尝试实现这一点,但我得到了 > Pages\albums.cshtml.cs(27,22): error CS4033: The 'await' operator can only be used within一个异步方法。考虑使用“异步”修饰符标记此方法并将其返回类型更改为“任务”。 > Pages\albums.cshtml.cs(27,22):错误 CS1061:“DbSet”不包含“GetAwaiter”的定义,并且没有可访问的扩展方法“GetAwaiter”接受“DbSet' 可以找到
  • 我现在已经修复了上述错误,因为我忘记从Albums = db.Albums; 中删除await,但现在我有“Pages\albums.cshtml(33,15): error CS0246:找不到类型或命名空间名称“专辑””
  • 您应该在代码中的某处定义一个 Album 类。您需要将其命名空间添加到文件顶部的 using 列表中。或者,您可以尝试 Visual Studio 中的快速修复选项。只需将光标移到带红色下划线的专辑单词上,然后按 Ctrl + 。然后使用建议接受添加
  • 是的,我有一个 Albums.cs 文件,尽管它位于我的实体文件夹中。它有namespace Project.Models,然后albums.cshtml.cs 有using Project.Models;,所以这似乎是你的建议。顺便说一句,我正在使用 Visual Studio Code(这是课程要求)。谢谢。
  • 有人告诉我 albums.cshtml 也需要@using Project.Models。我以为那只是为了专辑.cshtml.cs。所以它现在正在工作。非常感谢。
猜你喜欢
  • 2021-03-26
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
  • 2020-02-09
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 1970-01-01
相关资源
最近更新 更多