试图在外键上加入表,但输出不正确。 CRUD 也没有完全工作

Posted

技术标签:

【中文标题】试图在外键上加入表,但输出不正确。 CRUD 也没有完全工作【英文标题】:Trying to join table on foreign key, but output is incorrect. CRUD also not fully working 【发布时间】:2021-08-13 19:12:14 【问题描述】:

这是我的代码:

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:&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>

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:&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>

我应该解释一下ArtistIdAlbums表的外键,AlbumIdTracks表的外键。

艺术家数据正在传递到/Tracks,但出现了问题,因为所有输出都是以字母 A 开头的艺术家。所以似乎每个艺术家的名字都被重复了很多次?

我的代码还有另一个问题,因为我注意到当我尝试从我也创建的 /AlbumTracks 页面添加轨道时,我收到重定向页面的“找不到页面”错误,即使该 URL 似乎有效。虽然添加了曲目。

提前感谢您的任何指点。

GitHub repo

编辑:我决定忘记添加来自/Tracks 的曲目。我认为直接从/AlbumTracks 添加它们更有意义。

Edit2:重定向问题现已排序。我需要做的

        return RedirectToPage("/Albums/AlbumTracks", new id = id );

所以现在我需要能够将曲目添加为专辑的一部分。

Edit3:我实际上是这样工作的:

    <div><input asp-for="Track.Name" /></div>
    <div><input asp-for="Track.TrackId" /></div>
    <div><input asp-for="Track.AlbumId" /></div>

让用户手动输入他们想要添加曲目的专辑的AlbumId 显然并不理想。最好让系统直接从 URL 中获取AlbumId,如

 https://localhost:5001/Albums/AlbumTracks?id=361

【问题讨论】:

还有问题吗,还是你自己解决了? 好吧,我想出了一个“解决方法”,它至少表明数据库可以按照现状正确更新。但是对于用户来说,必须手动输入正确的AlbumId 值才能进行编辑显然并不理想。我真的更喜欢自动化解决方案。 【参考方案1】:

第一种方式

当你进入Albums/AlbumTracks?id=361页面时,你可以看到AlbumId等于361的曲目列表。如果你在这个页面中发布表单,请求url仍然是Albums/AlbumTracks?id=361。所以你在后处理程序中得到的id 就是你想要的AlbumId。如下更改您的 AlbumTracks.cshtml.cs

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

另一种方式是您可以在页面加载时使用AlbumId 设置输入。 AlbumTracks.cshtml 为特定的AlbumId 渲染了轨道,它们都拥有相同的AlbumId。您可以在 AlbumTracks.cshtml 中阅读AlbumId,如下所示:

@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:&nbsp;</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>

您可以获得AlbumId 的两种方式。

【讨论】:

啊,太棒了,非常感谢。我不太清楚的事情是ElementAt(0) 的用途,以及为什么需要name=?如果有人能告诉我那条线的伪代码会很棒,就像那条线到底在做什么/说什么?再次感谢。 模型绑定系统会通过匹配name来绑定模型。 asp-for 将自动生成 nameid 元素,它会生成 name=Tracks.ElementAt(0).AlbumId 但它与模型属性不匹配。这就是您需要指定name 的原因。 ElementAt(0) 用于返回序列中指定索引处的元素。参考:docs.microsoft.com/en-us/dotnet/api/…

以上是关于试图在外键上加入表,但输出不正确。 CRUD 也没有完全工作的主要内容,如果未能解决你的问题,请参考以下文章

我应该在外键上使用 onDelete=cascade 吗?

当我加入另一个表时,SUM 不正确

如何使用 EF 在外键上允许空值?

Symfony2 在外键上传递参数返回总是 null

在外键上按字段过滤

Oracle SQL Developer - 在外键上添加约束