C# 软删除存储库,同时保持属性私有

C# 软删除存储库,同时保持属性私有,c#,entity-framework,oop,repository,C#,Entity Framework,Oop,Repository,我有一套基于实体框架(EntityFramework,EF)的存储库,其中一些存储库处理可以软删除的实体(并非所有存储库都可以)。实体由EF自动生成。到目前为止,我已经: 可软删除的实体实现ICanBeSoftDeleted接口: public interface ICanBeSoftDeleted { bool IsDeleted { get; set; } } 对于这些实体,我使用实现ISoftDeleteRepository的存储库: public interface ISo

我有一套基于实体框架(EntityFramework,EF)的存储库,其中一些存储库处理可以软删除的实体(并非所有存储库都可以)。实体由EF自动生成。到目前为止,我已经:

  • 可软删除的实体实现ICanBeSoftDeleted接口:

    public interface ICanBeSoftDeleted
    {
        bool IsDeleted { get; set; }
    }
    
  • 对于这些实体,我使用实现ISoftDeleteRepository的存储库:

    public interface ISoftDeleteRepository<T> : IRepository<T> where T : class, ICanBeSoftDeleted    
    {
        void SoftDelete(T entity);   
        void SoftDelete(Expression<Func<T, bool>> where);
    }
    

    然而,这对我来说就像是一个补丁,我不认为它解决了更大的设计问题…

    你必须将EF类隐藏在墙后面,并映射到POCO;或者在将它们传递给使用者时,将它们作为接口(不声明setter)键入

    第二个选项使对象保持打开状态,以便通过反射设置“已删除”标志

    编辑:对您发布的代码的进一步分析会导致以下问题:

    您是否打算让API的使用者能够声明存储库

    在API中只公开非通用存储库(例如CustomerRepository、UserRepository、PurchaseRepository)似乎更明智

    然后,非泛型API形成一个干净的边界,您可以从中为API使用者将EF类与POCO分离

    public bool IsDeleted
    {
        get
        {
            return this.isDeleted;
        }
        //you can use protected if you intend to inherit the property and override it
        private set
        {
            this.isDeleted= value;
        }
    }
    
    编辑: 这里我描述了一个属性的创建,该属性可用于检测是否从有效位置调用了属性或功能

  • 在类中需要一个受保护的变量,以便验证IsDeleted属性。为了简单起见,我们假设它是一个字符串,并将其称为softDeleteKey

  • 这个变量需要一个公共setter,现在我们称它为setSoftDeleteKey

  • 您需要一个私有函数来检查密钥的有效性,如果有效则返回true,如果无效则返回false。我们称之为validateSoftDeleteKey

  • 实现一个名为isSoftDeleteKeyValid的只读属性,该属性将调用3中描述的函数

  • 在IsDeleted属性中,检查isSoftDeleteKeyValid。如果返回false,则抛出异常。如果IsDeleted成功,请将softDeleteKey设置为无效值

  • 在SoftDelete方法中,在设置IsDeleted属性之前,使用有效值调用setSoftDeleteKey。如果发生异常,则使用无效值调用setSoftDeleteKey


  • 我希望这些想法能对您有所帮助。

    您可以通过检查实体是否是在您的存储库中删除的ICanBeSoftDeleted的实现来实现吗

    使用此处的扩展名:

    公共静态类类型扩展
    {
    //http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/
    公共静态bool是的实现(此类型为baseType,类型为interfaceType)
    {
    返回baseType.GetInterfaces().Any(interfaceType.Equals);
    }
    }
    公共接口假定
    {
    无效删除(T实体);
    }
    公共类RepositoryBase:IRepository,其中T:class
    {
    公共作废删除(T实体)
    {
    if(typeof(T).i实现(typeof(icanbesofteded)))
    {
    ((ICanBeSoftDeleted)实体)。IsDeleted=true;
    //等
    }
    其他的
    {
    //硬删除
    }
    }
    }
    公共类客户:已删除
    {
    公共布尔被删除{get;set;}
    }
    公共类UOW
    {
    私有IRepository GetRepository()
    {
    返回(IRepository)新的RepositoryBase();
    }
    公共电子储蓄客户储蓄
    {
    得到
    {
    返回GetRepository();
    }
    }
    }
    公共接口已删除
    {
    布尔被删除{get;set;}
    }
    
    这个怎么样:

    public interface ICanBeSoftDeleted
    {
        bool IsDeleted { get; }
    }
    
    public abstract class CanBeSoftDeleted : ICanBeSoftDeleted
    {
        private bool _IsDeleted;
        public bool IsDeleted
        {
            get { return _IsDeleted; }
        }
    
        internal void SetIsDeleted(bool value) { _IsDeleted = value; }
    }
    

    然后模型可以从抽象类继承,而不是

    其思想是只公开非泛型存储库。问题是,如果ICCustomerRepository是公共的,那么它扩展的抽象类RepositoryBase也需要是公共的。这将允许人们自己创建扩展RepositoryBase的存储库,我不希望。。。有什么想法吗?我想使用EF生成的POCO作为DTO,所以我不会选择第一个选项。我考虑了第二种方法,从ICanBeSoftDeleted接口中删除“set”,并在存储库中设置反射。然而,这似乎有点“黑客”对我来说。。。是否存在任何性能问题?这不会阻止使用者使用与您相同的技术来摆弄已删除的标志。将setter设置为私有或受保护可防止我在SoftDelete()中修改其值然后您可以创建一个bool属性,当且仅当设置IsDeleted是一个有效操作时,该属性才为true。在IsDeleted属性中,忘记受保护的关键字,如果从无效位置调用setter,则在setter中抛出和异常。实现InvalidReferenceToIsDeleteSetterException并抛出该异常…我如何才能做到这一点?该方法将由引用它的外部工具从程序集内部和外部调用。你能展示一些示例代码吗?@chuwik,我已经用上一条消息中提到的bool属性的描述编辑了我的答案。谢谢编辑!然而,在这种情况下,反射看起来仍然是一个更干净的解决方案。可以软删除的实体也可以硬删除。硬删除方法在RepositoryBase上,而软删除方法仅在SoftRepositoryBase上添加,因此只有那些实体才能使用它。不幸的是,我们不能使用这种方法,所以用户可以调用SoftDelete(),将IsDeleted设置为true(并调用Update),但您不想让他们直接将isdelete设置为true。这是因为您担心他们可能会忘记调用Update()?不,这是因为软删除某些内容不仅仅如此;我简化了示例的方法,但我也希望始终记录活动,may
    public bool IsDeleted
    {
        get
        {
            return this.isDeleted;
        }
        //you can use protected if you intend to inherit the property and override it
        private set
        {
            this.isDeleted= value;
        }
    }
    
    public static class TypeExtensions
    {
        //http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/
        public static bool IsImplementationOf(this Type baseType, Type interfaceType)
        {
            return baseType.GetInterfaces().Any(interfaceType.Equals);
        }
    }
    
    public interface IRepository<T> 
    {
        void Delete(T entity);
    }
    
    public class RepositoryBase<T> : IRepository<T> where T : class
    {
        public void Delete(T entity)
        {
            if (typeof(T).IsImplementationOf(typeof(ICanBeSoftDeleted)))
            {
                ((ICanBeSoftDeleted)entity).IsDeleted = true;
                //etc
            }
            else
            {
                //hard delete
            }
        }
    }
    
    public class Customer : ICanBeSoftDeleted
    {
        public bool IsDeleted { get; set; }
    }
    
    public class UOW
    {
    
        private IRepository<T> GetRepository<T>()
        {
            return (IRepository<T>)new RepositoryBase<T>();
        }
    
        public IRepository<Customer> CustomerRepository
        {
            get
            {
                return GetRepository<Customer>();
            }
        }
    }
    
    public interface ICanBeSoftDeleted
    {
        bool IsDeleted { get; set; }
    }
    
    public interface ICanBeSoftDeleted
    {
        bool IsDeleted { get; }
    }
    
    public abstract class CanBeSoftDeleted : ICanBeSoftDeleted
    {
        private bool _IsDeleted;
        public bool IsDeleted
        {
            get { return _IsDeleted; }
        }
    
        internal void SetIsDeleted(bool value) { _IsDeleted = value; }
    }