如何避免在 Entity Framework 中重复相同的位置

How can avoid repeat same where in Entity Framework

在我的项目中,我不使用物理删除,我只对所有表使用逻辑 "soft delete"。

我将此子句用于所有查询:

.Where(row => row.IsDeleted == false)

我想要一种方法来避免在所有查询中重复此 where 子句。

我有这样的方法来获取数据:

public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
    return base.Set<TEntity>();
}

我这样称呼它:

_categories = _uow.Set<Category>();

我该怎么做?

第一个想法:

添加一个基础 class 并将 Deleted 列放入其中,并从该基础 class 继承所有 class。这样好吗?

我使用 UnitOfWork 和代码优先。

public class GenericRepository<TEntity> where TEntity : class
{
    internal MyContext context;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(MyContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IQueryable<TEntity> GetNonDeleted(Expression<Func<TEntity, bool>> filter = null)
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        query = query.Where(row => row.IsDeleted == false);

        return query;
    }
    // Other methods
}

我不会仅仅为了重复使用单个 属性 而创建基础 class。相反,我会创建一个接口和一个扩展方法来封装和重用 where 语句。类似于以下内容:

public static class EntityFrameworkExtentions
{
    public static ObservableCollection<TEntity> Alive<TEntity>(this DbSet<TEntity> set)
        where TEntity : class, ISoftDeleteAware
    {
        var data = set.Where(e => e.IsDeleted == false);
        return new ObservableCollection<TEntity>(data);
    }
}

接口声明

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

用法:

var coll = DbContext.Categories.Alive();

如果您从不删除任何内容,那么您可以使用基础实体 class 和 IsDelete 属性。之后,将此基本实体用于通用存储库。看起来像;

public abstract class BaseModel
{
    public BaseModel()
    {
        IsDelete = false;
        CreateDate = DateTime.Now;
    }
    [Key]
    public int Id { get; set; }
    public bool IsDelete{ get; set; }
    public virtual DateTime CreateDate { get; set; }
    public virtual DateTime UpdateDate { get; set; }
}

 public class YourClassHere : BaseModel
{
    //
}

public class Repository<T> : IRepository<T> where T : BaseModel
{
    private readonly IDbContext _context;
    private IDbSet<T> _entities;

    public Repository(IDbContext context)
    {
        this._context = context;
    }

    public T GetByIdByIgnoringDeleteStatus(int id)
    {
        return this.Entities.Find(id);
    }

    public T GetById(int id)
    {
        return this.Entities.Single(item => item.Id == id && !item.IsDelete);           

    }

    public void Create(T entity)
    {
        try
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            entity.CreateDate = DateTime.Now;
            this.Entities.Add(entity);                
            //this._context.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            var msg = string.Empty;

            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    msg += string.Format("Property: {0} Error: {1}",
                    validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
                }
            }

            var fail = new Exception(msg, dbEx);
            throw fail;
        }
    }

    public void Update(T entity)
    {
        try
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            entity.UpdateDate = DateTime.Now;
            this._context.SetModified(entity);
            //this._context.SaveChanges();

        }
        catch (DbEntityValidationException dbEx)
        {
            var msg = string.Empty;
            foreach (var validationErrors in dbEx.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, dbEx);
            throw fail;
        }
    }

    public void Delete(T entity)
    {
        try
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            entity.UpdateDate = DateTime.Now;
            this.Entities.Remove(entity);                
            //this._context.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            var msg = string.Empty;

            foreach (var validationErrors in dbEx.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, dbEx);
            throw fail;
        }
    }

    public virtual IQueryable<T> GetAll()
    {           
        return this.Entities;            
    }

    private IDbSet<T> Entities
    {
        get
        {
            if (_entities == null)
            {
                _entities = _context.Set<T>();
            }
            return _entities;
        }
    }

}

现在,您可以将 class 方法与删除状态结合使用。