我使用实体框架为我的后端逻辑编写了一个带有 MVC 的 Web 应用程序。我的问题是我有一个实体,该实体具有某些不应在更新时更改的字段。我不确定解决这个问题的最佳方法是什么。我的应用程序中将处理大量数据,所以我不能仅仅破解一个解决方案。
是否可以在 POCO 实体中将字段定义为只读?或者我应该编写验证所有更新的实体框架扩展类。是否可以在 EF 和实际数据库之间的映射文件中完成?
我对EF比较陌生,所以我希望你们中的一些人能给我一些指示!
谢谢!
我使用实体框架为我的后端逻辑编写了一个带有 MVC 的 Web 应用程序。我的问题是我有一个实体,该实体具有某些不应在更新时更改的字段。我不确定解决这个问题的最佳方法是什么。我的应用程序中将处理大量数据,所以我不能仅仅破解一个解决方案。
是否可以在 POCO 实体中将字段定义为只读?或者我应该编写验证所有更新的实体框架扩展类。是否可以在 EF 和实际数据库之间的映射文件中完成?
我对EF比较陌生,所以我希望你们中的一些人能给我一些指示!
谢谢!
如果您使用的是 .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 应该让事情变得更容易,而不是更难......)
好吧,我建议不要在视图中使用 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 自动映射,而是始终手动执行此操作,包括新项目。