从一个案例看MVC中DataContext和UpdateModel的工作原理(详解UpdateModel/SubmitChanges错误)
发布日期:2021-07-13 12:12:19 浏览次数:3 分类:技术文章

本文共 2380 字,大约阅读时间需要 7 分钟。

昨天遇到一段棘手的程序,尝试了各种方法,忽而在SubmitChanges的时候没反应(无错误,也不更新),忽而发生ChangeConflict,经过几个小时,终于大致理清了思路,也顺便把DataContext/UpdateModel/SubmitChanges给搞得更明白了一些,特此分享。

 

先大致看看代码:

 

xxController

{

        AgileRepository _repAgile = new AgileRepository(); //这里边是SubmitChanges/DateContext/Tables等属性,可取出下面提到的story

        SFCRepository _repSFC = new SFCRepository(); //相同,可取出下面提到的UDCs

   

        [HttpPost]

        public ActionResult Edit(int id, FormCollection collection)
        {
            Story story = _repAgile.GetStoryAt(id);

            try

            {
                UpdateModel(story);
                foreach (var udc in story.UDCs)
                {
                    UpdateModel(udc, udc.ID.ToString("D6"));
                }
                _repAgile.Save();

                _repSFC.Save(); //这里也是

                ...
            }
}

 

之所以出现红色的_repSFC.Save(),是因为story的一个属性List<IUDC> UDCs,也是需要在这个页面被更新的内容(在View中有控件与其对应),而它的Get过程最初是:

class Story

{

        public List<IUDC> UDCs 

        {
            get
            {

               SFCRepository rep = new SFCRepository(); 

                return rep.GetUDCs().Where(...);
            }
            set { }
        }
}

这里蓝色的rep和前面红色的rep不是同一个,所以如果从蓝色rep的当中取出UDCs并进行UpdateModel,而对另外一个无关的红色rep保存,什么也不会发生;而如果两者都取出UDCs并都曾经被UpdateModel,在Save(内部执行了SubmitChanges)的时候,会报出confilict changes exception,这个Exception极其麻烦而且不透明Google/MSDN上能找到一些资料但很多不工作。

 

其实,全部解决方法的秘诀其实就是:让取出数据的那个Repository执行Save操作(或者从内部看,是让取出数据的DataContext执行SubmitChanges操作)

 

蓝色rep的是个局部变量,活不到Save的时候了,只能用红色的那个rep了。代码改为下面这个就好了:

xxController

{

 SFCRepository _repSFC = new SFCRepository(); //下面取数据/保存的都是它。

 

[HttpPost]

public ActionResult Edit(int id, FormCollection collection)
{
    Story story = _repAgile.GetStoryAt(id);

    _repSFC.GetUDCsFor(story); //在这里边让_repSFC的DataContext取数据。

    try

    {
        UpdateModel(story);
        foreach (var udc in story.UDCs)
        {
             UpdateModel(udc, udc.ID.ToString("D6"));
        }
        _repAgile.Save();

        _repSFC.Save(); //这里会完成存储。

        ...
}

尽管能用了,但这段代码很不好,尤其GetUDCsFor,调用的位置很生硬,不好读也很容易出错。

最终还是这样最好:

 

外面:

            Story story = _repAgile.GetStoryAt(id);

            try

            {
                UpdateModel(story);
                foreach (var udc in story.UDCs)
                {
                    UpdateModel(udc, udc.ID.ToString("D6")); //Update的
                }
                story.SaveUDCs(); // 这个调用看着顺眼。
                _repAgile.Save();
                ...
            }
里边:

   public partial class Story : IUDCable, IItem

    {

        private SFCRepository _repSFC = new SFCRepository(); //这个方案里取数据/保存的都是它。_repSFC不再是个局部变量,生命周期正好和UDCs相同。

        public void SaveUDCs()
        {
            _repSFC.Save(); // 在这里保存
        }
        public List<IUDC> UDCs 
        {
            get
            {
                _repSFC.GetUDCOf(this, ref _udcs); //取数据。
                return _udcs;
            } 
        }
后面本来不应该再把_udcs传入GetUDCOf了,直接但因为别的IUDCable也要用到,所以封装了一个函数。

这个方案,取数据/存数据的都是Story内部的_repSFC,而且封装性更好,是最终结果。

 

最后重复一下在这种场景中发生问题时的解决方法的秘诀其实就是:让取出数据的那个Repository执行Save操作(或者从内部看,是让取出数据的DataContext执行SubmitChanges操作)

 

点击下载免费的敏捷开发教材:《》

 

转载地址:https://blog.csdn.net/cheny_com/article/details/6458304 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:IT人员及程序员怎样学好英语(关于如何利用极其有限的时间和条件学好英文)
下一篇:在Visual Studio的Server Explorer中怎样修改表名

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月04日 01时35分04秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章