通用存储库模式软删除

时间:2014-07-02 15:05:04

标签: c# entity-framework c#-4.0 repository-pattern

我创建了一个通用存储库(使用EF 6.1.1),我在几个项目中使用它并且它运行良好。 我实施了一个“软”的软件。删除功能,我们将数据标记为已删除,但实际上并未将其从数据库中删除。

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

我不确定如何以通用方式执行此操作,因为我不想将解决方案编码到每个respoitory中,这实际上违背了拥有通用存储库的原因。

这是我目前的Generic 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);
    }
}

对此的任何帮助都会很棒。

由于

2 个答案:

答案 0 :(得分:6)

有人建立了全局过滤器,您可以尝试从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上下文实例后在存储库构造函数或某个位置启用它,因为默认情况下禁用了过滤器。

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

答案 1 :(得分:0)

我遇到了同样的问题,但是我的解决方法几乎没有什么不同,我使用了通用的基本接口 IGenricInterface ,并以 IsDeleted 作为属性

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

并用于hardDelete

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

这是在ID上,但当然,您也可以在EnTity上完成