8

我使用实体框架为我的后端逻辑编写了一个带有 MVC 的 Web 应用程序。我的问题是我有一个实体,该实体具有某些不应在更新时更改的字段。我不确定解决这个问题的最佳方法是什么。我的应用程序中将处理大量数据,所以我不能仅仅破解一个解决方案。

是否可以在 POCO 实体中将字段定义为只读?或者我应该编写验证所有更新的实体框架扩展类。是否可以在 EF 和实际数据库之间的映射文件中完成?

我对EF比较陌生,所以我希望你们中的一些人能给我一些指示!

谢谢!

4

2 回答 2

15

如果您使用的是 .NET 4.5 和 EF 5(即 MVC 4),您可以简单地在相关的各个属性上设置 IsModified = false。这样做的好处是接近默认的开箱即用 MVC 约定。

例如,如果您有一个 CreatedBy 字段,在更新记录时不应触及该字段,请在控制器中使用以下内容:

[HttpPost]
    public ActionResult Edit(Response response)
    {
        if (ModelState.IsValid)
        {
            db.Entry(response).State = EntityState.Modified;
            db.Entry(response).Property(p => p.CreatedBy).IsModified = false;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(response);
    }

请注意,IsModified 行是默认控制器操作的唯一更改。

您必须在设置 .State = EntityState.Modified 之后放置这一行(这适用于整个记录并将记录添加到数据库上下文中)。

效果是 EF 不会在 SQL UPDATE 语句中包含该列。

我仍然(非常)震惊于没有类似于 [ReadOnly] 的 [InsertOnly] 或 [UpdateOnly] 属性。这似乎是 MVC 团队的重大疏忽。我错过了什么吗?

我对这个解决方案并不完全满意,因为它是一个 hack:当你真正想说的是“HANDS OFF”时,你告诉 EF 没有做出任何改变。这也意味着您必须在可以更新字段的任何地方使用此代码。最好在类属性上有一个属性。

(很抱歉发布到较旧的线程,但我在其他任何地方都没有看到这个解决方案。ViewModel 很强大但需要做很多工作,EF 应该让事情变得更容易,而不是更难......)

于 2012-11-21T23:24:10.133 回答
5

好吧,我建议不要在视图中使用 EF 类。最好的办法是构建 ViewModel 类并使用 Automapper 从 EF 类映射它们。

但是,当您更新数据库中的记录时,您可以控制 ViewModel 中的哪些字段用于更新 EF 类中的现有字段。

正常的过程是:

  • 使用 Id 从数据库中获取现有对象的最新版本。

  • 如果您使用的是乐观并发控制,请检查自 ViewModel 创建以来对象是否未更新(例如检查时间戳)。

  • 使用 ViewModel 对象中的必填字段更新此对象。

  • 将更新的对象持久化回数据库。

更新以包括 Automapper 示例:

假设您的 POCO 是

public class MyObject 
{
   public int Id {get;set;}
   public string Field1 {get;set;}
   public string Field2 {get;set;}
}

Field1 是您不想更新的字段。

您应该声明一个具有相同属性的视图模型:

public class MyObjectModel 
{
   public int Id {get;set;}
   public string Field1 {get;set;}
   public string Field2 {get;set;}
}

并在 Controller 的构造函数中在它们之间自动映射。

Mapper.CreateMap<MyObject, MyObjectModel>();

如果你愿意,你可以(虽然我更喜欢手动执行此操作,但也可以通过其他方式自动映射:

Mapper.CreateMap<MyObjectModel, MyObject>().ForMember(dest=>dest.Field1, opt=>opt.Ignore());

当您将日期发送到您的网站时,您将使用:

 var myObjectModelInstance = Mapper.Map<MyObject, MyObjectModel>(myObjectInstance);

创建视图模型。

保存数据时,您可能需要以下内容:

public JsonResult SaveMyObject(MyObjectModel myModel)
{
    var poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
    if(myModel.Id == 0 ) 
    {
       //New object
       poco.Field1 = myModel.Field1 //set Field1 for new creates only

    }
}

尽管我可能会删除上面对 Field1 的排除并执行以下操作:

public JsonResult SaveMyObject(MyObjectModel myModel)
{
   var poco;
   if(myModel.Id == 0)
   {
     poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
   }        
   else
   {
     poco = myDataLayer.GetMyObjectById(myModel.Id);
     poco.Field2 = myModel.Field2;
   }
   myDataLayer.SaveMyObject(poco);
}

请注意,我相信最佳实践不会让您从 ViewModel 自动映射,而是始终手动执行此操作,包括新项目。

于 2012-07-23T08:37:08.797 回答