通用存储库模式软删除

本文关键字:删除 模式 存储 | 更新日期: 2023-09-27 18:11:06

我创建了一个通用存储库(使用EF 6.1.1),我在几个项目中使用它,它工作得很好。我已经实现了一个"软"删除功能,我们将数据标记为已删除,但实际上并没有从数据库中删除它。

然后我可以过滤所有的查询,因为所有实体都继承自具有IsDeleted属性的基本实体。这一切都工作得很好,但它显然没有过滤掉任何"软删除"的子实体。

我不确定如何以一种通用的方式来做这件事,因为我不想在每个职责中都要过多地编写解决方案,这真的违背了拥有通用repo的理由。

这是我当前通用回购的一个例子

public sealed class MyRepository<T> : IRepository<T> where T : BaseEntity
{
    public String CurrentUser { get; set; }
    private readonly MyObjectContext context;
    private readonly Configuration configuration = ConfigurationManager.GetConfiguration();
    private IDbSet<T> entities;
    private IDbSet<T> Entities
    {
        get { return entities ?? (entities = context.Set<T>()); }
    }
    public MyRepository(MyObjectContext context, String userName = null)
    {
        this.context = context;
        var providerManager = new DataProviderManager(configuration);
        var dataProvider = (IDataProvider)providerManager.LoadDataProvider();
        dataProvider.InitDatabase();
        CurrentUser = userName;
    }
    public void Dispose()
    {
        //do nothing at the moment
    }
    public T GetById(Guid id)
    {
        return Entities.FirstOrDefault(x => x.Id == id && !x.IsDeleted);
    }
    public IQueryable<T> GetAll()
    {
        return Entities.Where(x => !x.IsDeleted);
    }
    public IQueryable<T> Query(Expression<Func<T, bool>> filter)
    {
        return Entities.Where(filter).Where(x => !x.IsDeleted);
    }
    public void Delete(T entity)
    {
        if (configuration.HardDelete)
        {
            HardDelete(entity);
        }
        else
        {
            SoftDelete(entity);
        }
    }
    private void HardDelete(T entity)
    {
        try
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            Entities.Attach(entity);
            Entities.Remove(entity);
        }
        catch (DbEntityValidationException ex)
        {
            var msg = string.Empty;
            foreach (var validationErrors in ex.EntityValidationErrors)
                foreach (var validationError in validationErrors.ValidationErrors)
                    msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
            var fail = new Exception(msg, ex);
            throw fail;
        }
    }
    private void SoftDelete(T entity)
    {
        entity.IsDeleted = true;
        Update(entity);
    }
}

如果有任何帮助就太好了。

谢谢

通用存储库模式软删除

有人建立了一个全局过滤器,你可以尝试它并从nuget EntityFramework.Filters安装它。

https://github.com/jbogard/EntityFramework.Filters

下面是一个如何使用它的例子。

public abstract class BaseEntity
{
    public int Id { get; set; }
    public bool IsDeleted { get; set; }
}
public class Foo : BaseEntity
{
    public string Name { get; set; }
    public ICollection<Bar> Bars { get; set; }
}
public class Bar : BaseEntity
{
    public string Name { get; set; }
    public int FooId { get; set; }
    public Foo Foo { get; set; }
}
public class AppContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Bar> Bars { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Registers and configures it first.
        DbInterception.Add(new FilterInterceptor());
        var softDeleteFilter = FilterConvention.Create<BaseEntity>("SoftDelete", 
            e => e.IsDeleted == false); // don't change it into e => !e.IsDeleted
        modelBuilder.Conventions.Add(softDeleteFilter);
    }
}

然后你可以在你的仓库构造函数中启用它,或者在db context实例创建后的某个地方启用它,因为默认情况下过滤器是禁用的。

using (var db = new AppContext())
{
    db.EnableFilter("SoftDelete");
    var foos = db.Foos.Include(f => f.Bars).ToArray(); // works on Include
}
using (var db = new AppContext())
{
    db.EnableFilter("SoftDelete");
    var foos = db.Foos.ToArray();
    foreach (var foo in foos)
    {
        var bars = foo.Bars; // works on lazy loading
    }
}
using (var db = new AppContext())
{
    db.EnableFilter("SoftDelete");
    var foos = db.Foos.ToArray();
    foreach (var foo in foos)
    {
        db.Entry(foo).Collection(f => f.Bars).Load(); // works on manual loading
    }
}

这个过滤器不再需要了。

public IQueryable<T> Query(Expression<Func<T, bool>> filter)
{
    return Entities.Where(filter);//.Where(x => !x.IsDeleted);
}

只要你启用了它。

public MyRepository(MyObjectContext context, String userName = null)
{
    this.context = context;
    if (!configuration.HardDelete)
    {
        this.context.EnableFilter("SoftDelete");
    }
}

我有同样的问题,但我的解决方法有点不同,我使用了一个通用的基接口IGenricInterfaceIsDeleted作为属性

public int DeletebyId(string Id)
 {
    var Ent = (IGenricInterface)_sitecontext.Set<TEntity>().Find(Id);
        Ent.IsDeleted = 1;
 }

 _sitecontext.Set<TEntity>().Remove(Ent);

这是在ID上当然你也可以在EnTity上设置