ef 核心多对多关系控制器

时间:2021-02-07 12:40:27

标签: c# asp.net-core entity-framework-core

我正在尝试使用 Entity Framework Core Database First 为用户和项目之间的多对多关系做一个控制器。我使用脚手架从数据库创建模型。/ create/Add 正在运行,但 CRUD 的其余部分不起作用( Edit, details )。我怎样才能做到这一点?我做错了什么?

当我点击编辑或获取详细信息时出现此错误 错误: 找不到此页面

创建用户项目表

CREATE TABLE [user_poject] (
    [user_id] INT , 
    [project_id] INT ,
    [user_roles] nvarchar(225)
    CONSTRAINT [user_project_PK] PRIMARY KEY ([user_id], [project_id]),

    CONSTRAINT fk_userProject_user
     FOREIGN KEY([user_id]) REFERENCES [user]([user_id]) ON DELETE CASCADE,

    CONSTRAINT fk_userProject_project 
     FOREIGN KEY([project_id]) REFERENCES [project]([project_id]) ON DELETE CASCADE
);

控制器:

public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var userPoject = await _context.UserPojects
                                   .Include(u => u.Project)
                                   .Include(u => u.User)
                                   .FirstOrDefaultAsync(m => m.UserId == id);
    if (userPoject == null)
    {
        return NotFound();
    }

    return View(userPoject);
}

// GET: UserPojects1/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var userPoject = await _context.UserPojects.FindAsync(id);
    if (userPoject == null)
    {
        return NotFound();
    }
    ViewData["ProjectId"] = new SelectList(_context.Projects, "ProjectId", "ProjectName", userPoject.ProjectId);
    ViewData["UserId"] = new SelectList(_context.Users, "UserId", "UserName", userPoject.UserId);
    return View(userPoject);
}

// POST: UserPojects1/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("UserId,ProjectId,UserRoles")] UserPoject userPoject)
{
    if (id != userPoject.UserId)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(userPoject);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!UserPojectExists(userPoject.UserId))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    ViewData["ProjectId"] = new SelectList(_context.Projects, "ProjectId", "ProjectName", userPoject.ProjectId);
    ViewData["UserId"] = new SelectList(_context.Users, "UserId", "UserName", userPoject.UserId);
    return View(userPoject);
}

用户项目模型:

public partial class UserPoject
{
    [Key]
    [Column("user_id" , Order =1)]
    public int UserId { get; set; }
    [Key]
    [Column("project_id" , Order =2)]
    public int ProjectId { get; set; }
    [Column("user_roles")]
    [StringLength(225)]
    public string UserRoles { get; set; }

    [ForeignKey(nameof(ProjectId))]
    [InverseProperty("UserPojects")]
    public virtual Project Project { get; set; }
    [ForeignKey(nameof(UserId))]
    [InverseProperty("UserPojects")]
    public virtual User User { get; set; }
}

用户模型:

  public partial class User
    {
        public User()
        {
            Tasks = new HashSet<Task>();
            UserPojects = new HashSet<UserPoject>();
            UserSprints = new HashSet<UserSprint>();
        }

        [Key]
        [Column("user_id")]
        public int UserId { get; set; }
        [Required]
        [Column("user_name")]
        [StringLength(50)]
        public string UserName { get; set; }
        [Column("user_email")]
        [StringLength(225)]
        public string UserEmail { get; set; }

        [InverseProperty(nameof(Task.User))]
        public virtual ICollection<Task> Tasks { get; set; }
        [InverseProperty(nameof(UserPoject.User))]
        public virtual ICollection<UserPoject> UserPojects { get; set; }
        [InverseProperty(nameof(UserSprint.User))]
        public virtual ICollection<UserSprint> UserSprints { get; set; }
    }

项目模型

 public partial class Project
    {
        public Project()
        {
            Sprints = new HashSet<Sprint>();
            UserPojects = new HashSet<UserPoject>();
        }

        [Key]
        [Column("project_id")]
        public int ProjectId { get; set; }
        [Column("project_name")]
        [StringLength(50)]
        public string ProjectName { get; set; }
        [Column("Project_description")]
        [StringLength(225)]
        public string ProjectDescription { get; set; }

        [InverseProperty(nameof(Sprint.Project))]
        public virtual ICollection<Sprint> Sprints { get; set; }
        [InverseProperty(nameof(UserPoject.Project))]
        public virtual ICollection<UserPoject> UserPojects { get; set; }
    }

DBContext-Fluent API


            modelBuilder.Entity<UserPoject>(entity =>
            {
                entity.HasKey(e => new { e.UserId, e.ProjectId })
                    .HasName("PK__user_poj__5279AEEECFA4D53D");

                entity.HasOne(d => d.Project)
                    .WithMany(p => p.UserPojects)
                    .HasForeignKey(d => d.ProjectId)
                    .HasConstraintName("FK__user_poje__proje__33D4B598");

                entity.HasOne(d => d.User)
                    .WithMany(p => p.UserPojects)
                    .HasForeignKey(d => d.UserId)
                    .HasConstraintName("FK__user_poje__user___32E0915F");
            });

2 个答案:

答案 0 :(得分:0)

我看到了一些事情,首先您需要使用“PUT”而不是“POST”来进行更新操作。缓存策略将允许折叠冗余条目。此外,在没有 POST 的情况下,还有 PUT 的排序规则。客户端以任何顺序发送 POST 操作并获得相同的结果应该是安全的。

但是对于原始问题,您将要告诉上下文您已经修改了实体。

来自Microsoft example

// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

如果这仍然给您带来问题,请同时删除显式绑定,您可以使用属性适当地装饰模型类。

答案 1 :(得分:0)

<块引用>

当我单击编辑或获取详细信息时,此错误出现错误: 找不到此页面

public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var userPoject = await _context.UserPojects
                                   .Include(u => u.Project)
                                   .Include(u => u.User)
                                   .FirstOrDefaultAsync(m => m.UserId == id);
    if (userPoject == null)
    {
        return NotFound();
    }

    return View(userPoject);
}

正如我们之前讨论的,通过使用上面的代码,如果id为空,它将返回NotFound页面。因此,该问题与索引页面上的编辑和详细信息超链接有关。请参考以下代码(在ActionLink方法中,使用主键添加id参数):

@model IEnumerable<netcore5.Models.UserPoject>     
<table class="table">
    <thead>
           @*header*@
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.UserId)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ProjectId)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.UserRoles)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new {  id=item.UserId }) |
                @Html.ActionLink("Details", "Details", new {  id=item.UserId }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.UserId  })
            </td>
        </tr>
}
    </tbody>
</table>

此外,在 Startup.Configure 方法中,如果您使用的是默认的 MVC 路由模板,如下所示:

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");

            endpoints.MapRazorPages();
        });

然后,您还可以使用以下 Anchor Tag Helper 添加带有 id 参数的链接:

        <td>
            <a asp-action="Edit" asp-route-id="@item.UserId">Edit</a> |
            <a asp-action="Details" asp-route-id="@item.UserId">Details</a> |
            <a asp-action="Delete" asp-route-id="@item.UserId">Delete</a>
        </td>

结果是这样的:

enter image description here

参考:

Anchor Tag Helper in ASP.NET Core

Tutorial: Implement CRUD Functionality - ASP.NET MVC with EF Core