我正在使用Entity Framework为我的后端逻辑编写一个带有MVC的Web应用程序。我的问题是我有一个实体,它有一些永远不应该在更新时改变的字段。我不确定解决这个问题的最佳方法是什么。在我的应用程序中会处理大量数据,所以我不能只是破解解决方案。
是否可以在POCO实体中将字段定义为只读?或者我应该编写验证所有更新的实体框架扩展类。可以在EF和实际数据库之间的映射文件中完成吗?
我是EF的新手,所以我希望你们中的一些人能给我一些指示!
谢谢!
答案 0 :(得分:12)
如果您使用的是.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行是默认控制器操作的唯一更改。
你必须把这行放在AFTER设置.State = EntityState.Modified(它作为一个整体应用于记录并将记录添加到db上下文中)。
结果是EF不会在SQL UPDATE语句中包含此列。
我仍然(非常)感到震惊的是没有类似于[ReadOnly]的[InsertOnly]或[UpdateOnly]属性。这似乎是MVC团队的一次重大监督。我错过了什么吗?
我对这个解决方案并不完全满意,因为它是一个黑客攻击:你告诉EF,当你真正想说的是“HANDS OFF”时,没有做出任何改变。这也意味着您必须在可以更新字段的任何地方使用此代码。在类属性上有一个属性会更好。
(抱歉发布到较旧的帖子,但我没有在其他任何地方看到这个解决方案.ViewModels很强大但很多工作,EF应该让事情变得更容易,而不是更难......)
答案 1 :(得分:3)
我建议不要在View中使用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的构造函数中对它们进行Automap。
Mapper.CreateMap<MyObject, MyObjectModel>();
如果你愿意,你可以(虽然我更喜欢手动执行此操作,但也可以自动化另一种方式:
Mapper.CreateMap<MyObjectModel, MyObject>().ForMember(dest=>dest.Field1, opt=>opt.Ignore());
当您向网站发送日期时,您将使用:
var myObjectModelInstance = Mapper.Map<MyObject, MyObjectModel>(myObjectInstance);
创建viewModel。
保存数据时,您可能需要以下内容:
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自动执行,而是始终手动执行此操作,包括新项目。