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" />
View Code

 

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;
View Code

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); } };
View Code

 

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);
View Code

 

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; } }
View Code

具體的操作,這個應該都清楚了

        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; }
View Code

 

最后很最重要的一點是:在關閉窗體后需要釋放對象,不然大量數據加長時間運行會導致客戶端內存泄露的

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時才出現問題)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM