0

我有一组基于实体框架 (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”属性,只读取它或删除调用该方法的实体。现在他们可以这样做,因为 setter 是公开的。

我怎样才能改变我的代码设计才能做到这一点?我无法更改 ICanBeSoftDeleted 并删除设置器,因为那样我将无法从 SoftDeleteRepositories 修改它。

谢谢

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

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

    Update(entity);
}

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

4

4 回答 4

1

您可以通过检查实体是否是您的 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; }
}
于 2013-07-11T10:10:17.693 回答
1

您必须将 EF 类保留在墙后并映射到 POCO;或者在将它们交给消费者时将它们键入为接口(不声明设置器)。

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

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

您是否打算让 API 的使用者能够声明 Repositories ?

在您的 API 中只公开非通用存储库似乎更明智 - 例如 CustomerRepository、UserRepository、PurchaseRepository。

然后,非泛型 API 形成一个清晰的边界,您可以将 EF 类与 API 使用者的 POCO 分开。

于 2013-07-10T16:41:32.863 回答
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; }
}

然后模型可以从抽象类继承

于 2013-07-12T13:34:25.093 回答
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. 您需要该变量的公共设置器,我们现在将其称为 setSoftDeleteKey。

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

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

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

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

我希望这些想法对你有所帮助。

于 2013-07-10T16:48:15.980 回答