假设我有一个包含A列和B列的数据库表,我使用Visual Studio设计器为该表创建了一个Linq对象。所有字段都标记为NOT NULL。
现在我正在尝试使用典型的MVC表单编辑和模型绑定来编辑此记录,但字段B不需要是可编辑的,因此我不在表单中包含它。
当post处理程序绑定对象时,它不会填充字段B,将其保留为null。现在当我保存对象时,我得到一个数据库错误,说字段B不能为NULL。
要保存的代码类似于:
m_DataContext.MyObjects.Attach(myObject);
m_DataContext.Refresh(RefreshMode.KeepCurrentValues, myObject);
m_DataContext.SubmitChanges();
我如何让它工作?我是否需要在表单中包含字段B作为隐藏字段 - 我真的不想这样做,因为它可能会被其他用户同时更新,我不想踩它。
我发现这个问题的解决方案围绕在应用更改之前获取与数据上下文关联的实体对象。有几种方法可以做到这一点,我在下面的单独答案中对此进行了描述。
答案 0 :(得分:3)
这种方法使LINQ偏向直接SQL:
public override void SaveMyObject(MyObject o)
{
// Submit
m_DataContext.ExecuteCommand("UPDATE MyObjects SET A={0} WHERE ID={1}", o.ID, o.A);
}
我喜欢这种方法,因为它很简单。尽管我喜欢LINQ,但我无法证明这个问题的混乱。
答案 1 :(得分:1)
此方法在绑定发生之前使用自定义模型绑定器创建实体对象并与数据上下文关联。
public class MyObjectBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
MyObject a = ((MyObjectController)controllerContext.Controller).Repository.GetMyObjectForUpdate(bindingContext.ValueProvider["ID"].AttemptedValue.ToString());
return a;
}
}
然后,存储库创建对象并将其与数据上下文相关联:
public Object GetMyObjectForUpdate(string id)
{
MyObject o=new MyObject();
o.ID=id;
m_DataContext.Articles.Attach(o);
m_DataContext.Refresh(RefreshMode.KeepCurrentValues);
return o;
}
需要将操作处理程序归因于使用模型绑定程序...
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditMyObject([ModelBinder(typeof(MyObjectBinder))] MyObject o)
{
if (!ModelState.IsValid)
return View("EditMyObject", a);
Repository.SaveMyObject(a);
return RedirectToAction("Index");
}
最后SaveMyObject只调用datacontext.SubmitChanges()。
为此,我还需要将所有列的更新检查属性设置为Never(在dbml文件中)。
总的来说,这种方法有效,但很麻烦。
答案 2 :(得分:0)
此方法使用两个实体对象,一个用于模型绑定,另一个用于LINQ:
public override void SaveMyObject(MyObject o)
{
// Create a second object for use with linq and attach to the data context
MyObject o2 = new MyObject();
o2.ID = o.ID;
m_DataContext.Articles.Attach(o2);
m_DataContext.Refresh(RefreshMode.KeepCurrentValues);
// Apply fields edited by the form
o2.A = o.A;
// Submit
m_DataContext.SubmitChanges();
}
此程序不需要在控制器中进行任何特殊处理(即:没有自定义模型绑定),但仍需要 要在dbml文件中将Update Check属性设置为Never。
答案 3 :(得分:-1)
您可以添加一个时间戳字段,并在页面上选中一个时间戳字段(也隐藏时间戳字段)。如果用户更新了记录,则会返回并发错误并刷新页面,或者在用户更改时保持不变。