• 热门专题

Devexpress + wcf +ef 批量更新处理

作者:遗忘海岸  发布日期:2014-10-22 19:51:53
Tag标签:Devexpress  +  wcf  +ef  批量更新处理  
  • 项目结构:

    1.客户端:Winform,

    2.数据访问:EF4.0(从数据库生成模型-懒人必需这样)

    3.DTO:直接使用EF实体

    4.服务端:WCF 托管在IIS中采用basicHttp帮定(这样可以客户端的代理类就不需要每次人肉释放了)

    Winform或asp.net ,MVC中每次一般只操作一条记录或者对多条记录进行相同的操作,这个时候我们知道需要对记录或记录集合进行的是那种CURD.

    但是如果直接将获取的记录集合 List<T> 帮定到BindingSource并关联DataGridView(或gridControl),并且使用gridControl提供的CURD功能时,怎么才能知道那些记录需要进行那些CURD操作呢?
    解决方案暂时不提,  凭借gridcontrol提供的强大功能,一般的单个数据表CRUD可以直接拖控件完成,要知道在一般的企业项目中有大量的基础数据收集维护功能,尤其当你是一个人在战斗时,能拖个控件就把CURD完成时是多么的有幸福,而且现在是采用标准的三层结构,你可以对服务层做下反向代理以实现负载均衡了。

    解决办法

    界面如下

    EF默认在Context中保存对象的状态,但是当对象通过WCF传输后,我们在两端获取对方传输过来的对象多是Detached状态,而且在客户端典型的用法是直接将List<T>帮定到BindingSrouce上,根本不使用EFContext对象进行跟着。

    1.那么解决首先是要在客户端对List<T>的对象进行跟踪    要进行跟踪懒人加吊丝的做法当然不是自己实现EF跟踪接口,而是直接使用EFContext对象,    那客户端EFContext对象直接SaveChanges连数据库怎么办?    参考下面的配置,将EF连接字符串的关键信息全部换成*,这样你就能在WinForm中正常的New出Context对象了

      <add name="FireSeatEntities" connectionString="metadata=res://*/FireSeatDB.csdl|res://*/FireSeatDB.ssdl|res://*/FireSeatDB.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=****;initial catalog=****;persist security info=True;user id=****;password=***;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

    2.将服务端加载对象添加到Context环境中 2.1.首先是第一次加载,一般是由一个查询引起的

                    var dicItems= Fetch<IDicItemsService>().Take(0,100,string.Format("it.DicNo='{0}'", cur.DicNo), "it.OrderId");
                    foreach (var item in dicItems)
                    {
                        EntCtx.Attach(item); //这里进行附加
                    }
                    //绑定到BindingSource
                    sys_DicItemsBindingSource.DataSource = dicItems;

    2.2.对gridControl进行的添加擅长操作做提示并关联到Context

                dataNavigator1.ButtonClick += (s, ie) => {
                    try
                    {
                        #region 
                        if (ie.Button.ButtonType == NavigatorButtonType.Append)
                        {
                            var dicNo = dicNoTextEdit.Text.Trim();
                            if (string.IsNullOrWhiteSpace(dicNo)) throw new Exception("请输入字典编号!");
    
                            var cur = sys_DicItemsBindingSource.AddNew() as Sys_DicItems;
                            cur.DicNo = dicNo;
                            EntCtx.CreateObjectSet<Sys_DicItems>().AddObject(cur);
    
                            ie.Handled = true;
                        }
    
                        else if (ie.Button.ButtonType == NavigatorButtonType.Remove)
                        {
                            var cur = sys_DicItemsBindingSource.Current as Sys_DicItems;
                            if ( MessageBox.Show("确认删除吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Cancel)
                            {
                                ie.Handled = true;
                                return;
                            }
    
                            
                            EntCtx.DeleteObject(cur);
    
                        }
                        else if (ie.Button.ButtonType == NavigatorButtonType.EndEdit)
                        {
                            gridView1.CloseEditor();
                        }
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        ie.Handled = true;
                        ErrMsg(ex.Message);
                    }
                };

    2.3.对gridcontrol 进行 大量 添加,修改,删除后点保存

             gridView1.CloseEditor();
                sys_DicItemsBindingSource.EndEdit();
    
       //获取进行了CUD的记录集合
                var addList = EntCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Select(osEnt => osEnt.Entity as Sys_DicItems).ToList();
                var delList = EntCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted).Select(osEnt => osEnt.Entity as Sys_DicItems).ToList();
                var editList = EntCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Select(osEnt => osEnt.Entity as Sys_DicItems).ToList();
    
    
    
    
    
                #region 更新字典条目
    
                EntityUpdateSet<Sys_DicItems> retDs = null;
                Action act = () =>
                {
                    var ds = new EntityUpdateSet<Sys_DicItems>(addList, delList, editList) {ReturnAddList=true,ReturnEditList=true };
                    retDs = Fetch<IDicItemsService>().BatchUpdate(ds);
                };
                
                InvokeService(act, "更新列表");
    
               //将服务器返回记录归并到本地
                for (int i = 0; i < retDs.AddList.Count; i++)
                {
                    CloneEFModel<Sys_DicItems, Sys_DicItems>(retDs.AddList[i], addList[i]);
                }
                for (int i = 0; i < retDs.EditList.Count; i++)
                {
                    CloneEFModel<Sys_DicItems, Sys_DicItems>(retDs.EditList[i], editList[i]);
                }
           
                //将所以记录设置成Unchange状态
                EntCtx.AcceptAllChanges();
                sys_DicItemsBindingSource.ResetBindings(false);

    3.服务端的定义

    EntityUpdateSet定义了CUD操作对应的列表

        public class EntityUpdateSet<T>
             where T : System.Data.Objects.DataClasses.EntityObject
        {
            public EntityUpdateSet()
            {
                AddList = new List<T>();
                ReturnAddList = true;
                DelList = new List<T>();
                ReturnDelList = false;
                EditList = new List<T>();
                ReturnEditList = false;
            }
            public EntityUpdateSet(List<T> addList, List<T> delList, List<T> editList):this()
            {
                this.AddList = addList;
                this.DelList = delList;
                this.EditList = editList;
            }
            public List<T> AddList { get; set; }
            public bool ReturnAddList { get; set; }
            public List<T> DelList { get; set; }
            public bool ReturnDelList { get; set; }
            public List<T> EditList { get; set; }
            public bool ReturnEditList { get; set; }
            
        }

    具体的操作,这个应该都清楚了

            public EntityUpdateSet<T> BatchUpdate(EntityUpdateSet<T> ds)
            {
                BatchUpdateVerify(ds);
                 var set = Ctx.CreateObjectSet<T>();
                foreach (var addItem in ds.AddList)
                {
                    set.AddObject(addItem);
                }
                foreach (var delItem in ds.DelList)
                {
                    set.Attach(delItem);
                    set.DeleteObject(delItem);
                }
                foreach (var editItem in ds.EditList)
                {
                    set.Attach(editItem);
                    Ctx.ObjectStateManager.ChangeObjectState(editItem, System.Data.EntityState.Modified);
                }
                Ctx.SaveChanges();
                if (!ds.ReturnAddList) ds.AddList.Clear();
                if (!ds.ReturnDelList) ds.DelList.Clear();
                if (!ds.ReturnEditList) ds.EditList.Clear();
    
                return ds;
    
    
    
            }

    最后很最重要的一点是:在关闭窗体后需要释放对象,不然大量数据加长时间运行会导致客户端内存泄露的

    protected override void OnClosed(EventArgs e)   

          {            

             base.OnClosed(e);   

              sys_DicItemsBindingSource.Dispose();      

             sys_DicBindingSource.Dispose();        

            if (EntCtx != null) EntCtx.Dispose();     

        }

      最后之最后,最最总要的一点是,NND即使使用了上面的释放代码,内存一样只增不减,那位兄弟帮忙解决下啊 (首先排除是WCF代理对象未释放问题,Fetch<IDicItemsService> 获取缓存的代理对象,进行不停调用,不会出现内存问题,只有把EFModel attch到客户端的Context时才出现问题)

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规