You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

更新含外键的SpeakerForm模型时出现临时值错误求助

问题描述

尝试从数据库获取SpeakerForm模型,修改后通过表单提交更新。此前使用_context.Attach(Model).State = EntityState.Modified;方法能正常工作,但在新页面复用该方法时,出现如下错误:

错误信息

InvalidOperationException: The property 'SpeakerForm.SpeakerFormId' has a temporary value while attempting to change the entity's state to 'Modified'. Either set a permanent value explicitly, or ensure that the database is configured to generate values for this property.
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, bool acceptChanges, bool modifyProperties)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, bool acceptChanges, bool modifyProperties, Nullable<EntityState> forceStateWhenUnknownKey, Nullable<EntityState> fallbackState)
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.set_State(EntityState value)
LosBarriosEvents.Pages.SpeakerFormsEditModel.OnPostAsync() in Edit.cshtml.cs
+
        _context.SpeakerForms.Attach(Form).State = EntityState.Modified;

模型定义

SpeakerForm主模型

using System.ComponentModel.DataAnnotations;

namespace LosBarriosEvents.Models;

public class SpeakerForm
{
    [Key]
    public int SpeakerFormId { get; set; }

    public string Title { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string Duration { get; set; } = string.Empty;

    //Navigation Properties
    public string SpeakerId { get; set; }
    public Speaker? Speaker { get; set; }
}

关联的Speaker外键模型

using System.ComponentModel.DataAnnotations;

namespace LosBarriosEvents.Models
{
    public class Speaker
    {
        [Key]
        public string SpeakerId { get; set; } = default!;//PK

        public string firstName { get; set; } = string.Empty;
        public string lastName { get; set; } = string.Empty;
        public string email { get; set; } = string.Empty;
        public string phoneNumber { get; set; } = string.Empty;

        //Navigation Properties
        public List<SpeakerForm>? SpeakerForms { get; set; }
    }
}

后端代码(Edit.cshtml.cs)

using System.Security.Claims;
using LosBarriosEvents.Areas.Identity.Data;
using LosBarriosEvents.Authorization;
using LosBarriosEvents.Data;
using LosBarriosEvents.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;

namespace LosBarriosEvents.Pages;

[Authorize(Roles = "Administrators,Speakers")]

public class SpeakerFormsEditModel : PageModel
{

    private readonly ILogger<SpeakerFormsEditModel> _logger;
    private readonly ApplicationDbContext _context;
    private readonly UserManager<LosBarriosUser> _userManager;


    public SpeakerFormsEditModel(ILogger<SpeakerFormsEditModel> logger, ApplicationDbContext context, UserManager<LosBarriosUser> userManager)
    {
        _logger = logger;
        _context = context;
        _userManager = userManager;
    }

    [BindProperty]
    public SpeakerForm Form { get; set; }

    public IActionResult OnGet(int? id)
    {
        var userId = _userManager.GetUserId(User);

        SpeakerForm frm = _context.SpeakerForms.FirstOrDefault(f => f.SpeakerFormId == id);

        if (frm == null)
        {
            return NotFound();
        }

        Form = frm;

        return Page();
    }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        var isAuthorized = User.IsInRole(UserRoles.LosBarriosEventsSpeakerRole) || User.IsInRole(UserRoles.LosBarriosEventsAdministratorRole);

        if (!isAuthorized)
        {
            return Forbid();
        }

        _context.SpeakerForms.Attach(Form).State = EntityState.Modified;

        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

前端Razor页面(edit.cshtml)

@page
@model SpeakerFormsEditModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">Edit Speaker Form</h1>
</div>

<form id="SpeakerEditForm" method="post">
    <h2>Edit Form</h2>
    <hr />
    <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>

    <div class="form-floating mb-3">
        <input asp-for="Form.Title" class="form-control" aria-required="true" placeholder="Lecture Title" />
        <label asp-for="Form.Title">Lecture Title</label>
        <span asp-validation-for="Form.Title" class="text-danger"></span>
    </div>
    <div class="form-floating mb-3">
        <input asp-for="Form.Description" class="form-control" aria-required="true" placeholder="Description" />
        <label asp-for="Form.Description">Description of Lecture</label>
        <span asp-validation-for="Form.Description" class="text-danger"></span>
    </div>
    <div class="form-floating mb-3">
        <input asp-for="Form.Duration" class="form-control" aria-required="true" placeholder="Lecture Duration" />
        <label asp-for="Form.Duration">Duration</label>
        <span asp-validation-for="Form.Duration" class="text-danger"></span>
    </div>
    <div class="form-floating mb-3">
        <input asp-for="Form.SpeakerId" type="hidden"/>
    </div>
    <div class="form-floating mb-3">
        <input asp-for="Form.Speaker" type="hidden"/>
    </div>


    <button id="SpeakerFormSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Submit</button>
</form>
<a asp-page="./Index">Back to Forms</a>

解决方案

问题根源

表单提交时未传递SpeakerFormId主键值,导致后端绑定的Form对象中SpeakerFormId为默认值0(临时值)。EF Core无法识别这是一个已存在的实体,因此设置状态为Modified时抛出错误。其他页面能正常运行是因为表单包含了主键的隐藏字段。

修复方案1:添加主键隐藏字段

在前端表单中添加SpeakerFormId的隐藏输入框,确保提交时传递主键值:

<div class="form-floating mb-3">
    <input asp-for="Form.SpeakerFormId" type="hidden"/>
</div>

添加位置可放在SpeakerId隐藏字段附近。

修复方案2:优化后端更新逻辑(更安全)

避免直接使用Attach+Modified的方式,改为从数据库查询原实体后更新属性,这种方式能防止覆盖未提交的字段,且EF Core会自动跟踪实体变化:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    var isAuthorized = User.IsInRole(UserRoles.LosBarriosEventsSpeakerRole) || User.IsInRole(UserRoles.LosBarriosEventsAdministratorRole);
    if (!isAuthorized)
    {
        return Forbid();
    }

    // 从数据库获取要修改的实体
    var existingForm = await _context.SpeakerForms.FindAsync(Form.SpeakerFormId);
    if (existingForm == null)
    {
        return NotFound();
    }

    // 更新需要修改的属性
    existingForm.Title = Form.Title;
    existingForm.Description = Form.Description;
    existingForm.Duration = Form.Duration;
    // 若允许修改SpeakerId,可取消下面注释
    // existingForm.SpeakerId = Form.SpeakerId;

    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

内容的提问来源于stack exchange,提问作者J D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 22:07:02