【问题标题】:Generic Repository with Soft Delete Feature具有软删除功能的通用存储库
【发布时间】:2012-11-08 23:16:29
【问题描述】:

我有一个通用的存储库实现。我正在使用 asp.net mvc c#,代码优先实体框架。

我创建了一个名为 ISoftDelete 的接口:

public interface ISoftDelete
{
    bool IsDeleted { get; set; }
}

我在我的基础存储库中实现了 Delete 和 GetById,如下所示:

    public virtual void Delete(T entity)
    {
        if (entity is ISoftDelete)
        {
            ((ISoftDelete)entity).IsDeleted = true;
        }
        else
        {
            dbset.Remove(entity);
        }
    }

    public virtual T GetById(long id)
    {
        T obj = dbset.Find(id);
        if (obj is ISoftDelete)
        {
            if (((ISoftDelete)obj).IsDeleted)
                return null;
            else
                return obj;
        }
        else
        {
            return obj;
        }
    }

现在,我有 2 个问题。

1) 这种方法是好方法吗?有任何与性能相关的问题吗?

2) 我原来在基础仓库中的GetAll函数是这样的:

    public virtual IEnumerable<T> GetAll()
    {
            return dbset.ToList();
    }

当 T 派生自 ISoftDelete 时,我应如何修改它以列出 IsDeleted == false 的记录?

谢谢!

【问题讨论】:

    标签: asp.net-mvc ef-code-first repository-pattern


    【解决方案1】:

    1) 每次需要知道时都检查if (entity is ISoftDelete) 似乎不太好。如果您确定不会在其他任何地方检查它,那可能没问题。就性能而言,如果您消除具有IsDeleted == true 的记录并且从不从数据库中获取它们会更好。您可能需要派生一个新的基础存储库,它会覆盖这些方法并为 ISoftDelete 对象实现新逻辑。

    public abstract class BaseRepository<T>
    {
        // protected dbset;
    
        public virtual void Delete(T entity)
        {
            dbset.Remove(entity);
        }
    
        public virtual T GetById(long id)
        {
            return dbset.Find(id);
        }
    
        public virtual IEnumerable<T> GetAll()
        {
            return dbset.ToList();
        }
    }
    
    public abstract class SoftDeleteRepository<T> : BaseRepository<T> where T : ISoftDelete
    {
        public override void Delete(T entity)
        {
             entity.IsDeleted = true;
        }
    
        public override T GetById(long id)
        {
            return (from t in dbSet
                    where !t.IsDeleted && t.Id == id select t)
                    .FirstOrDefault();
        }
    
        public override IEnumerable<T> GetAll()
        {
            return (from t in dbset where !t.IsDeleted select t).ToList();
        }
    }
    
    public static class RepositoryFactory
    {
         public static BaseRepository<T> GetInstance<T>()
         {
              // pseudo code
              if (typeof(T) implements ISoftDelete)
                   return repository of T which extends SoftDeleteRepository
              return repository of T which extends BaseRepository
         }
    }
    

    2) 可能类似于

     return (from t in dbset  where 
           (t is ISoftDelete && !(t as ISoftDelete).IsDeleted) || 
           !(t is ISoftDelete))
     .ToList();
    

    【讨论】:

    • public override T GetById(long id) 此函数在 t.Id 上抛出错误。
    • 如果您在 BaseRepository 中放置了 GetById(long id) 方法,这意味着您假设项目中的任何实体实例都应该具有 long Id 属性。为了满足这个要求,您可以定义一个接口,例如IEntity { long Id { get; } },并将其应用于所有实体。并从此界面派生您的ISoftDeleteinterface ISoftDelete : IEntity { bool IsDeleted { get; set; } }。现在您的 SoftDeleteRepository 确定每个 T 实例都将具有 Id 和 IsDeleted 属性。
    • 我对 Generic Repository 概念有点陌生,所以我并不完全理解 RepositoryFactory 概念。这将如何实施?您能否详细说明或分享一个详细说明此概念的链接?
    【解决方案2】:

    你的方法对我来说似乎很好。我认为除了在 isDeleted 条件下的测试之外,几乎没有性能损失,这没关系。对于 getAll 你可以试试这个代码:

        public virtual IEnumerable<T> GetAll()
        {
            var queryable = dbset;
            if (typeof(ISoftDelete).IsAssignableFrom(typeof(T)))
            {
                queryable = queryable.Where(q => q.IsDeleted == false);
            }
    
            return queryable.ToList();
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 2020-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-10
      • 2021-05-02
      相关资源
      最近更新 更多