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

时间:2013-07-10 16:35:23

标签: c# entity-framework oop repository

我有一组基于实体框架(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);
    }
    
  • 我还有一个基类,SoftDeleteRepositoryBase,它扩展了RepositoryBase并添加了软删除方法:

    public abstract class SoftDeleteRepositoryBase<T> : RepositoryBase<T> where T : class, ICanBeSoftDeleted
    {
        public virtual void SoftDelete(T entity)
        {
            entity.IsDeleted = true;
            Update(entity);
        }
    
        public virtual void SoftDelete(Expression<Func<T, bool>> where)
        {
            var entitiesToDelete = GetMany(where).AsEnumerable();
            foreach (T entity in entitiesToDelete)
            {
                this.Delete(entity);
            }
        }
    }
    

一切正常。但是,此代码是分发给直接调用存储库的用户的内部库的一部分,我不希望它们更改“IsDeleted”属性,只读取它或删除调用该方法的实体。现在他们可以做到这一点,因为二传手是公开的。

如何更改代码设计才能执行此操作?我无法更改ICanBeSoftDeleted并删除setter,因为那样我就无法从SoftDeleteRepositories修改它。

由于

更新目前我通过从界面中删除“set”并使用反射设置存储库中的值来解决问题:

public virtual void Delete(T entity)
{
    PropertyInfo propertyInfo = entity.GetType().GetProperty("IsDeleted");
    propertyInfo.SetValue(entity, true);

    Update(entity);
}

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

4 个答案:

答案 0 :(得分:1)

您必须将EF课程保留在墙后并映射到POCO;或者在将它们交给消费者时将它们键入界面(不会声明设置者)。

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

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

您是否打算让API的消费者能够声明存储库?

仅暴露非通用存储库似乎更明智 - 例如您的API中的CustomerRepository,UserRepository,PurchaseRepository。

非通用API然后形成一个干净的边界,您可以从中将API类与API消费者的POCO分开。

答案 1 :(得分:0)

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

编辑: 这里我描述了一个属性的创建,该属性可用于检测是否从有效位置调用属性或功能。

  1. 您需要在类中使用受保护的变量来验证IsDeleted属性。为简单起见,我们假设它是一个字符串,并将其称为softDeleteKey。

  2. 您需要为该变量设置一个公共setter,现在我们称之为setSoftDeleteKey。

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

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

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

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

  7. 我希望这些想法可以帮到你。

答案 2 :(得分:0)

您可以通过检查实体是否是RepositoryBase中ICanBeSoftDeleted的实现来实现吗?

使用此处的扩展程序: http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/

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

答案 3 :(得分:0)

这个怎么样:

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

然后模型可以继承抽象类