简体   繁体   English

ASP.NET MVC3代码优先错误 - 尝试更新实体

[英]ASP.NET MVC3 Code-First Error- attempting to update entity

I've checked this question and it seems to be related to what I need, but does not answer it exactly. 我已经检查了这个问题 ,它似乎与我需要的东西有关,但并没有完全回答。

I have an entity (Sql Compact using EF Code First via MVC3- if that wasn't clear from the title) for an "Issue" (generic issue tracking, just for my own education understanding of how MVC3 works). 我有一个实体(Sql Compact使用EF Code First通过MVC3-如果标题不清楚的话)“问题”(通用问题跟踪,只是为了我自己的教育理解MVC3如何工作)。 The Issue class has a CreatedBy property (Int reference to a User who Created the Issue) and a CreatedDate property (DateTime). Issue类具有CreatedBy属性(对创建问题的用户的Int引用)和CreatedDate属性(DateTime)。 When I use the scaffolded code to update (modified only to prevent some updated date fields from being modified by the user): 当我使用scaffolded代码进行更新时(仅修改以防止某些更新的日期字段被用户修改):

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

I receive the error mentioned in the linked question (conversion of a datetime2 data type to a datetime data type etc., etc.,) 我收到链接问题中提到的错误(将datetime2数据类型转换为日期时间数据类型等,等)

When I step through the code, it appears my CreatedBy and CreatedDate properties are not contained in the instance of issue that the controller is passing around. 当我单步执行代码时,看起来我的CreatedBy和CreatedDate属性不包含在控制器传递的issue实例中。 When I try to fix that by grabbing another copy of the issue from the db, and updating those to values: 当我尝试通过从数据库中获取问题的另一个副本并将其更新为值来解决此问题时:

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

I get the concurrency violation: An object with the same key already exists in the ObjectStateManager. 我得到并发冲突:ObjectStateManager中已存在具有相同密钥的对象。 The ObjectStateManager cannot track multiple objects with the same key. ObjectStateManager无法使用相同的键跟踪多个对象。

So, how do I get EF to see the date which is already set in the DB (so it doesn't try to update the CreatedDate to 1/1/0001) without violating concurrency? 那么,如何在不违反并发的情况下让EF查看数据库中已设置的日期(因此它不会尝试将CreatedDate更新为1/1/0001)?

Edit Okay... I found it. 编辑好的......我找到了。 I was, apparently, looking for @Html.HiddenFor(model => model.[property]) and adding the editor to the view anyway. 显然,我正在寻找@Html.HiddenFor(model => model.[property])并将编辑器添加到视图中。 That seems a little silly and round-about to me, but it does work without having to add custom code to detach one object and substitute an updated one. 这对我来说似乎有点愚蠢和圆润,但它确实有效,无需添加自定义代码来分离一个对象并替换更新的对象。

The short answer is that you've already loaded the entity into the context with the Find and you cannot later attach another one. 简短的回答是,您已经使用“ Find将实体加载到上下文中,之后无法附加另一个实体。

You are left with two options: 你有两个选择:

  • Detach the first instance, then attach the second 分离第一个实例,然后附加第二个实例
  • Copy the fields from the second instance to the first 将字段从第二个实例复制到第一个实例

I'll share code for the first option. 我会分享第一个选项的代码。 First, add a Detach method to your DbContext implementation: 首先,在DbContext实现中添加一个Detach方法:

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

Then call Detach instead of setting the variable to null 然后调用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");
}

If the CreateDate and CreatedBy fields are not in the edit form, the update action object will not have the db values. 如果CreateDate和CreatedBy字段不在编辑表单中,则更新操作对象将不具有db值。

The additional call to the db and resetting, as Ed's answer describes, can be avoided if you include those fields in the edit form. 如编辑表单中包含这些字段,可以避免在Ed的答案描述的情况下对数据库和重置的附加调用。 Then the normal model binding should pick them up and give them back to you on the update. 然后,正常的模型绑定应该接收它们并在更新时将它们返回给您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM