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时才出现问题)

时间: 2024-08-03 09:22:09

Devexpress + wcf +ef 批量更新处理的相关文章

EF 批量更新

EF5批量插入 在园里看到别人的文章,将下面两个属性设为false会提高批量插入的效率, db.Configuration.AutoDetectChangesEnabled = false; db.Configuration.ValidateOnSaveEnabled = false; 于是自己试了下,确实速度更快,代码如下: // 批量插入 public ActionResult BulkInsert() { int count = 1000; string check = null; Mov

EF 批量更新/删除数据

在网上找了很久,得到的答案是"Entity Framework 中不能同时更新多条记录",历经这么多版本,居然还没有这种基本功能,我真的很无语了.还要先查询出来,然后再对实体更新或删除,那效率可想而知了-- 在网上找了找解决方案,比如说这个 EF架构~性能高效的批量操作(Update篇) 感觉在剑走偏锋,里面实际是在拼Sql(当然EF最终也是拼SQL),我却不喜欢这么干,完全没有Linq的感觉,也很别扭. 最后又找到个开源库,又是老外解决的 Entity Framework Exten

Entity Framework Extended Library (EF扩展类库,支持批量更新、删除、合并多个查询等)

今天乍一看,园子里居然没有关于这个类库的文章,实在是意外毕竟已经有很多介绍EF使用的文章了. E文好的可以直接看https://github.com/loresoft/EntityFramework.Extended 也可以在nuget上直接安装这个包,它的说明有点过时了,最新版本已经改用对IQueryable<T>的扩展,而不是DbSet<T>(已经标记为弃用),所以跟我一样有隔离癖好的就可以大胆使用了.下面介绍如何批量删除.更新.查询. 批量删除 本来我们需要这样删除 ? //

EF批量操作数据与缓存扩展框架

前言 在原生的EF框架中,针对批量数据操作的接口有限,EF扩展框架弥补了EF在批量操作时的接口,这些批量操作包括:批量修改.批量查询.批量删除和数据缓存,如果您想在EF中更方便的批量操作数据,这个扩展将对您来说很有用. 下载安装 这个框架支持通过NuGet包管理器进行安装,你可以在包管理器中搜索:EntityFramework.Extended,最简单的方法就是程序包管理控制台进行安装,安装命令如下: PM > Install - Package EntityFramework.Extended

LINQ To SQL在N层应用程序中的CUD操作、批量删除、批量更新

原文:LINQ To SQL在N层应用程序中的CUD操作.批量删除.批量更新 0. 说明 Linq to Sql,以下简称L2S.    以下文中所指的两层和三层结构,分别如下图所示: 准确的说,这里的分层并不是特别明确:(1) 生成的DataContext(Linq t0 SQL Runtime)和Entity是放在一个文件中的,物理上不能切割开来:上图只是展示逻辑上的结构.(2) 拿上图右边的三层结构来说,鉴于第(1)点,UI层就可以跨越BusinessLogic层,直接访问L2S层,这可能

MySQL批量更新不同表中的数据

今天翻到以前写的批量更新表中的数据的存储过程,故在此做一下记录. 当时MySQL中的表名具有如下特征,即根据需求将业务表类型分为了公有.私有和临时三种类型,即不同的业务对应三张表,而所做的是区分出是什么类型(公有.私有.临时)的业务表对数据的固定字段做统一规律的处理. 下面为当时所编写的存储过程: BEGIN DECLARE done INT; DECLARE v_table_name VARCHAR(100); DECLARE v_disable VARCHAR(100); DECLARE v

mysql 批量更新与批量更新多条记录的不同值实现方法

在mysql中批量更新我们可能使用update,replace into来操作,下面来给各位详细介绍mysql 批量更新与性能吧! mysql更新语句很简单,更新一条数据的某个字段,一般这样写: 复制代码代码如下: UPDATE mytable SET myfield = 'value' WHERE other_field = 'other_value'; 如果更新同一字段为同一个值,mysql也很简单,修改下where即可: 复制代码代码如下: UPDATE mytable SET myfie

WCF客户端配置以及代理-----基于DDD领域驱动设计的WCF+EF+WPF分层框架(4)

写在最前面:转载请注明出处 目录置顶: 关于项目--------------------基于DDD领域驱动设计的WCF+EF+WPF分层框架(1) 架构搭建--------------------基于DDD领域驱动设计的WCF+EF+WPF分层框架(2) WCF服务端具体实现---------基于DDD领域驱动设计的WCF+EF+WPF分层框架(3) WCF客户端配置以及代理-----基于DDD领域驱动设计的WCF+EF+WPF分层框架(4) Domain具体实现------------基于DD

DataTable 获取列名 DataTable批量更新至数据库

好久没写东西了,这几个月也没下功夫钻研技术,愧疚啊.说下最近刚学会的DataTable 的用法吧,新手适合看下. 1 DataTable 获取列名 在处理数据的时候大家都会用到模型,从datatable遍历数据的时候可以用datatable的columns属性获取列名,然后就可以动态的用datatable 生成一个josn字符串,然后再讲json字符串转化成你想要的model,是不是很方便?. 下面是将datatable转化为json数组的方法. private string DataTable