如何避免在 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 方法与删除状态结合使用。
在我的项目中,我不使用物理删除,我只对所有表使用逻辑 "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 方法与删除状态结合使用。