如何指示实体框架不更新模型的属性

时间:2011-10-13 17:23:46

标签: c# asp.net-mvc-3 entity-framework entity-framework-4 entity-framework-4.1

我正在使用Asp.net MVC和Entity框架(下面的代码仅用于演示)

我有一个类似下面的模型

  public class Person
    {
        [Key]
        public int Id { get; set; }

        [Required]
        public string FirstName { get; set; }

        /*Time at which person was created*/
        public DateTime CreatedOn { get; set; }  /*should not change once created*/
    }

在创建+插入新人时,我手动设置CreatedOn datetime属性。

更新时

我的视图只有一个文本框

 @using (Html.BeginForm())
        {
            @Html.LabelFor(a => a.FirstName) 
            @Html.EditorFor(a => a.FirstName) 
            @Html.ValidationMessageFor(a => a.FirstName)            
            <br />
            <input type="submit" name="name" value="submit" />
}

控制器

    [HttpPost]
    public ActionResult EditPerson(Person person)
    {
        if (ModelState.IsValid)
        {
            db.Entry(person).State = EntityState.Modified;
            db.SaveChanges();

            /* ----------------
              Error here
              ----------------- 
             */

            return RedirectToAction("ListPerson");
        }
        return View(person);            
    }

我在代码中的上述位置收到错误,错误:The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.错误似乎很明显,因为控制器内部收到的person对象具有默认时间值,实体框架也尝试更新该字段。

我的问题是如何指示实体框架不更新属性。假设在上面的情况下,对于CreatedOn属性我说实体框架不更新它,我不会得到错误。

我在[Editable(false)]上尝试了CreatedOn属性,但它没有用。

有一些选项,比如,在更新之前我首先从数据库加载现有实体并复制createdOn属性.....

我希望你知道,在我的真实模型中有许多我不想更新的属性,并且有很多这样的模型,所以我期待一些现实的答案。

编辑1

我首先使用代码。

1 个答案:

答案 0 :(得分:2)

您获得的具体错误是因为CreatedOn被设置为默认值。当您进行回发时,您必须从数据库加载对象,更新它然后保存它。通过这样做,您将停止您遇到的这个特定错误。

您似乎正在使用实体模型作为控制器中的模型。我不推荐这个。通过专门为帖子创建模型,您可以从模型中删除任何不可编辑的字段。然后,您可以将模型值从ViewModel复制到实体模型。这可以防止用户编辑您可能不希望他们编辑的属性。

public class PersonViewModel
{
    [Key]
    public int Id { get; set; }

    [Required]
    public string FirstName { get; set; }
}

这是一个好主意的主要原因是有人可能会试图猜测哪些值也可能起作用。例如,如果您的Person对象上有一个名为IsAdministrator的属性,我会截取帖子并添加&IsAdministrator=on&Adminstrator=on&Admin=on(以覆盖几个基数),那么ModelBinder将获取该值并将其应用于模型。现在我刚成为你系统的管理员。我知道如果你有很多模型,这是很多工作,但是将你的实体模型用于帖子绝对不是一个好主意。

您还可以使用Bind属性来限制映射器绑定的项目。

public ActionResult EditPerson([Bind(Exclude = "CreatedOn")] Person person)

这应该可以防止绑定器绑定该特定属性。但是,它不会解决您的问题,因为创建person对象时始终设置默认值。解决此问题的唯一方法是从数据库加载对象,然后更新/保存它。