【问题标题】:ASP.NET MVC3 Code-First Error- attempting to update entityASP.NET MVC3 Code-First Error-试图更新实体
【发布时间】:2011-05-16 19:29:58
【问题描述】:

我检查了this question,它似乎与我的需要有关,但没有准确回答。

我有一个实体(Sql Compact using EF Code First via MVC3-如果标题中不清楚的话)用于“问题”(一般问题跟踪,仅用于我自己对 MVC3 工作原理的教育理解)。问题类具有 CreatedBy 属性(对创建问题的用户的 Int 引用)和 CreatedDate 属性 (DateTime)。当我使用脚手架代码更新时(修改只是为了防止某些更新的日期字段被用户修改):

        if (ModelState.IsValid)
        {
            issue.LastActivity = (DateTime?)DateTime.Now.Date;
            if (issue.ClosedBy != null) issue.ClosedDate = (DateTime?)DateTime.Now.Date;
            startingIssue = null;
            db.Entry(issue).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }

我收到链接问题中提到的错误(将 datetime2 数据类型转换为 datetime 数据类型等)

当我单步执行代码时,我的 CreatedBy 和 CreatedDate 属性似乎不包含在控制器正在传递的 issue 的实例中。当我尝试通过从数据库中获取问题的另一个副本并将其更新为值来解决此问题时:

        var startingIssue = db.Issues.Find(issue.IssueId);
        if (ModelState.IsValid)
        {
            if (issue.CreatedBy != startingIssue.CreatedBy) issue.CreatedBy = startingIssue.CreatedBy;
            if (issue.CreatedDate != startingIssue.CreatedDate) issue.CreatedDate = startingIssue.CreatedDate;
            issue.LastActivity = (DateTime?)DateTime.Now.Date;
            if (issue.ClosedBy != null) issue.ClosedDate = (DateTime?)DateTime.Now.Date;
            startingIssue = null;
            db.Entry(issue).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }

我得到并发冲突:ObjectStateManager 中已存在具有相同键的对象。 ObjectStateManager 无法跟踪具有相同键的多个对象。

那么,如何让 EF 在不违反并发性的情况下查看已在数据库中设置的日期(因此它不会尝试将 CreatedDate 更新为 1/1/0001)?

编辑 好吧……我找到了。显然,我正在寻找@Html.HiddenFor(model => model.[property]) 并将编辑器添加到视图中。这对我来说似乎有点愚蠢和迂回,但它确实可以工作,而无需添加自定义代码来分离一个对象并替换一个更新的对象。

【问题讨论】:

    标签: c# asp.net asp.net-mvc-3 sql-server-ce


    【解决方案1】:

    简短的回答是,您已经使用 Find 将实体加载到上下文中,以后无法附加另一个。

    你有两个选择:

    • 分离第一个实例,然后附加第二个
    • 将字段从第二个实例复制到第一个实例

    我将分享第一个选项的代码。首先,将Detach 方法添加到您的DbContext 实现中:

    public void Detach(object entity)
    {
        var objectContext = ((IObjectContextAdapter)this).ObjectContext;
        objectContext.Detach(entity);
    }
    

    然后调用Detach而不是将变量设置为null

    var startingIssue = db.Issues.Find(issue.IssueId);
    if (ModelState.IsValid)
    {
        if (issue.CreatedBy != startingIssue.CreatedBy) issue.CreatedBy = startingIssue.CreatedBy;
        if (issue.CreatedDate != startingIssue.CreatedDate) issue.CreatedDate = startingIssue.CreatedDate;
        issue.LastActivity = (DateTime?)DateTime.Now.Date;
        if (issue.ClosedBy != null) issue.ClosedDate = (DateTime?)DateTime.Now.Date;
    
        // startingIssue = null;
        db.Detach(startingIssue);
    
        db.Entry(issue).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    

    【讨论】:

    • 那行得通。谢谢。我会等着看是否有其他人碰巧提供了一个更优雅的解决方案,但如果没有,我会选择你的作为接受的答案。
    • 我遇到了类似的问题。我在创建新记录时需要设置表(CreatedBy、CreatedOn)上的审核字段,但我不想将它们传递给我的 MVC 站点上的编辑页面。因此,当正在编辑新记录时,我必须从数据库中读取当前审计值,然后更新传入对象,然后再将其保存到 DBContext 中。为此,我需要 .Find(id),获取当前值,然后分离。我的问题/答案在这里stackoverflow.com/questions/8145635/…
    • @Ed:我想给+100k ..我在这个问题上浪费了几个小时!谢谢!!
    【解决方案2】:

    如果 CreateDate 和 CreatedBy 字段不在编辑表单中,则更新操作对象将没有 db 值。

    如果您在编辑表单中包含这些字段,则可以避免对数据库的额外调用和重置,如 Ed 的回答所述。然后正常的模型绑定应该会拾取它们并在更新时将它们返回给您。

    【讨论】:

    • 确实可以,但它们也可以编辑。我确实已经显示了这些值,就像文本一样。如果我为值添加编辑器字段,我将不得不采取其他方式来阻止用户确定他们的问题实际上是在 10 天前而不是今天早些时候创建的。
    • 是的,将它们设置为隐藏字段将使绑定工作,但如果字段需要保持不变,则会将这些字段暴露给操作,这是不好的。
    猜你喜欢
    • 2011-10-29
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 2014-11-11
    相关资源
    最近更新 更多