Lind.DDD.ILogicDeleteBehavor~邏輯刪除的實現
關于邏輯刪除
對(dui)于邏輯(ji)刪除(chu)之(zhi)前的(de)(de)做(zuo)(zuo)(zuo)法是(shi)(shi)在(zai)(zai)實(shi)體類中加(jia)個(ge)(ge)字(zi)段,一般是(shi)(shi)status,其(qi)中一種(zhong)(zhong)狀態是(shi)(shi)刪除(chu),當然也有其(qi)它做(zuo)(zuo)(zuo)法,如加(jia)個(ge)(ge)bool的(de)(de)字(zi)段IsDeleted,這些其(qi)實(shi)都(dou)過于武斷,即它在(zai)(zai)基類里加(jia)上后,所(suo)以實(shi)體類都(dou)會有這種(zhong)(zhong)特性,而(er)對(dui)于現(xian)實(shi)的(de)(de)數(shu)據表(biao),可能不顯示(shi)這種(zhong)(zhong)邏輯(ji)刪除(chu)的(de)(de)特性,如關系表(biao),日(ri)志表(biao),可能刪除(chu)就是(shi)(shi)物(wu)理上的(de)(de)直接(jie)delete,而(er)這種(zhong)(zhong)刪除(chu)字(zi)段加(jia)上去,我們的(de)(de)做(zuo)(zuo)(zuo)也是(shi)(shi)在(zai)(zai)業務層手動調用update方法,或者在(zai)(zai)底層提(ti)供(gong)一個(ge)(ge)delete方法的(de)(de)重載,總之(zhi),感覺不是(shi)(shi)很爽!
看了ABP的(de)軟刪(shan)除(chu)之(zhi)后(hou),對(dui)大叔有(you)了新的(de)啟發,即(ji)提出(chu)一(yi)個邏輯刪(shan)除(chu)的(de)接口,所以(yi)需要這個字段(duan)的(de)實(shi)體(ti)都去實(shi)現這個接口即(ji)可!
邏輯刪除的接口(對實體屬性的裝飾)
/// <summary> /// 具有邏輯(ji)刪(shan)除(chu)的接口(kou),實體需(xu)要實現這個接口(kou),將IsDeleted實現 /// 在倉儲實現類中,delete方法判(pan)斷實體是否實現了(le)ILogicDeleteBehavor這個接口(kou),然后再決(jue)定是否邏(luo)輯刪(shan)除 /// </summary> public interface ILogicDeleteBehavor { /// <summary> /// 是否已經刪(shan)除,默認為false /// </summary> bool IsDeleted { get; set; } }
這個接口很干凈,只有一個屬性,這個屬性用來標識刪除的狀態,true表示已經刪除,在進行select操作時我們需要將這個狀態過濾,在delete方法里,我們也可以通過判斷當前實體是否屬于ILogicDeleteBehavor接口(kou)而對它采取是(shi)否(fou)進行邏輯刪(shan)除(chu)!
實體多繼承一個接口,完成某個特定的功能
public partial class WebManageUsers : Lind.DDD.Domain.Entity, ILogicDeleteBehavor, IStatusBehavor { #region IStatusBehavor 成員 public Status DataStatus { get; set; } #endregion #region ILogicDeleteBehavor 成員 public bool IsDeleted { get; set; } #endregion public WebManageUsers() { this.WebManageRoles = new HashSet<WebManageRoles>(); this.WebDepartments = new HashSet<WebDepartments>(); } [DisplayName("登陸(lu)名"), Required] public string LoginName { get; set; } [DisplayName("密碼"), Required] public string Password { get; set; } [DisplayName("真實姓名(ming)"), Required] public string RealName { get; set; } [DisplayName("手(shou)機")] public string Mobile { get; set; } [DisplayName("電子郵(you)件")] public string Email { get; set; } [DisplayName("描述(shu)")] public string Description { get; set; } [DisplayName("操作者")] public string Operator { get; set; } [DisplayName("所屬項目")] public Nullable<int> WebSystemID { get; set; } public virtual ICollection<WebManageRoles> WebManageRoles { get; set; } public virtual ICollection<WebDepartments> WebDepartments { get; set; } }
本例采(cai)用的(de)是(shi)EF的(de)CodeFirst方式(shi),所以需要將自己定義實(shi)體,然后根據實(shi)體自動生成(cheng)數據庫.
刪除方法直接判斷實體是否實現了某個接口
public void Delete(TEntity item) { if (item != null) { if (item is ILogicDeleteBehavor) { //邏(luo)輯刪除(chu) var pkList = GetPrimaryKey().Select(i => i.Name); var entityType = typeof(TEntity); List<object> primaryArr = new List<object>(); foreach (var primaryField in pkList) { primaryArr.Add(entityType.GetProperty(primaryField).GetValue(item, null)); } var old = this.Find(primaryArr.ToArray()); (old as ILogicDeleteBehavor).IsDeleted = true; this.Update(old); } else { //物理刪除 Db.Set<TEntity>().Attach(item as TEntity); Db.Entry(item).State = EntityState.Deleted; Db.Set<TEntity>().Remove(item as TEntity); this.SaveChanges(); } } }
上面(mian)的設置,對(dui)于在(zai)列表里(li)(li)刪除某個對(dui)象已經可以實現了,而(er)如(ru)何(he)去(qu)過(guo)濾(lv)列表里(li)(li)的記錄呢,當(dang)然直接在(zai)DbSet<TEntity>()里(li)(li)去(qu)過(guo)濾(lv)是最(zui)好的,但沒(mei)有(you)直接的方式,因為我(wo)們的IsDeleted屬性沒(mei)有(you)對(dui)外暴(bao)露,而(er)對(dui)于Linq to Entity來說(shuo),你無法在(zai)查詢表達式中輸(shu)
入EDM之(zhi)外的(de)元素名(那也不認,它只認實體(ti)類型),還好在ABP里我找到了不錯的(de)方(fang)法,就是在數(shu)據上下(xia)文(wen)的(de)OnModelCreating方(fang)法上,添加過濾(lv)器,這個(ge)過濾(lv)器需要(yao)我們(men)安(an)裝EntityFramework.DynamicFilters包,直接用Nuget可(ke)以(yi)安(an)裝.
ModelBuilder.Filter完成對集合的全局過濾
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Filter("LogicDelete", (Lind.DDD.Domain.ILogicDeleteBehavor d) => d.IsDeleted, false); }
這樣在(zai)所有Linq Select語句之前都會(hui)添加d.IsDeleted==false這個參數完(wan)成邏輯刪除的過(guo)濾功能(neng)!
是不是很爽,很酷!
對于實體中其它的比較有特點的屬性,而又不是全局的屬性,我們都可以使用接口的方式進行定義,這類似于裝飾模式,即將某個屬性裝飾成某個接口,而在程序的另一端直接去操作這個接口即可.