• Lind.DDD.ILogicDeleteBehavor~逻辑删除的实现


    回到目录

    关于逻辑删除

    对于逻辑删除之前的做法是在实体类中加个字段,一般是status,其中一种状态是删除,当然也有其它做法,如加个bool的字段IsDeleted,这些其实都过于武断,即它在基类里加上后,所以实体类都会有这种特性,而对于现实的数据表,可能不显示这种逻辑删除的特性,如关系表,日志表,可能删除就是物理上的直接delete,而这种删除字段加上去,我们的做也是在业务层手动调用update方法,或者在底层提供一个delete方法的重载,总之,感觉不是很爽!

    看了ABP的软删除之后,对大叔有了新的启发,即提出一个逻辑删除的接口,所以需要这个字段的实体都去实现这个接口即可!

    逻辑删除的接口(对实体属性的装饰)

       /// <summary>
        /// 具有逻辑删除的接口,实体需要实现这个接口,将IsDeleted实现
        /// 在仓储实现类中,delete方法判断实体是否实现了ILogicDeleteBehavor这个接口,然后再决定是否逻辑删除
        /// </summary>
        public interface ILogicDeleteBehavor
        {
            /// <summary>
            /// 是否已经删除,默认为false
            /// </summary>
            bool IsDeleted { get; set; }
        }

    这个接口很干净,只有一个属性,这个属性用来标识删除的状态,true表示已经删除,在进行select操作时我们需要将这个状态过滤,在delete方法里,我们也可以通过判断当前实体是否属于ILogicDeleteBehavor接口而对它采取是否进行逻辑删除!

    实体多继承一个接口,完成某个特定的功能

     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("登陆名"), Required]
            public string LoginName { get; set; }
            [DisplayName("密码"), Required]
            public string Password { get; set; }
            [DisplayName("真实姓名"), Required]
            public string RealName { get; set; }
            [DisplayName("手机")]
            public string Mobile { get; set; }
            [DisplayName("电子邮件")]
            public string Email { get; set; }
            [DisplayName("描述")]
            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; }
    
        }

    本例采用的是EF的CodeFirst方式,所以需要将自己定义实体,然后根据实体自动生成数据库.

    删除方法直接判断实体是否实现了某个接口

     public void Delete(TEntity item)
            {
                if (item != null)
                {
                    if (item is ILogicDeleteBehavor)
                    {
                        //逻辑删除
                        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();
                    }
    
                }
            }

    上面的设置,对于在列表里删除某个对象已经可以实现了,而如何去过滤列表里的记录呢,当然直接在DbSet<TEntity>()里去过滤是最好的,但没有直接的方式,因为我们的IsDeleted属性没有对外暴露,而对于Linq to Entity来说,你无法在查询表达式中输

    入EDM之外的元素名(那也不认,它只认实体类型),还好在ABP里我找到了不错的方法,就是在数据上下文的OnModelCreating方法上,添加过滤器,这个过滤器需要我们安装EntityFramework.DynamicFilters包,直接用Nuget可以安装.

    ModelBuilder.Filter完成对集合的全局过滤

      protected override void OnModelCreating(DbModelBuilder modelBuilder)
       {
                base.OnModelCreating(modelBuilder);
                modelBuilder.Filter("LogicDelete", (Lind.DDD.Domain.ILogicDeleteBehavor d) => d.IsDeleted, false);
       }

    这样在所有Linq Select语句之前都会添加d.IsDeleted==false这个参数完成逻辑删除的过滤功能!

    是不是很爽,很酷!

    对于实体中其它的比较有特点的属性,而又不是全局的属性,我们都可以使用接口的方式进行定义,这类似于装饰模式,即将某个属性装饰成某个接口,而在程序的另一端直接去操作这个接口即可

    回到目录

  • 相关阅读:
    转:每个架构师都应该研究下康威定律
    使用OpenShiftFQ上外网
    关系模式设计
    数据库应用系统工程过程
    数据库系统
    四种常见 Git 工作流比较
    Git 进阶指南
    C#高性能TCP服务的多种实现方式
    浮动广告
    <span></span>
  • 原文地址:https://www.cnblogs.com/lori/p/5580437.html
Copyright © 2020-2023  润新知