在 FindAsync 上应用全局查询过滤器
Apply Gobal Query Filter on FindAsync
我在 ASP.NET Core API
:
中实施了 软删除 查询行为
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
modelBuilder.Entity<OneOfMyEntity>().HasQueryFilter(entity => !entity.IsDeleted);
modelBuilder.Entity<AnotherEntity>().HasQueryFilter(entity => !entity.IsDeleted);
}
现在这在我的 Repository
中封装了我的 DbContext
:
的两个常用方法中效果很好
public async Task<List<TEntity>> GetAllExcludeDeleted()
{
return await _context.Set<TEntity>().ToListAsync();
}
public async Task<List<TEntity>> GetAll()
{
return await _context.Set<TEntity>().IgnoreQueryFilters().ToListAsync();
}
但是,当我在我的存储库上编写集成测试时,我意识到它不是 DbContext.FindAsync(int)
方法的解决方案:
public async Task<TEntity> GetById(int id)
{
return await _context.Set<TEntity>().FindAsync(id);
}
我的解决方案
我可以想象用 FirstOrDefault(e => !e.IsDeleted)
替换 FindAsync(id)
来处理这个问题
真题
你们怎么看,有什么比用 Linq query
替换 FindAsync
更好的解决方案?与 FindAsync
相比,FirstOrDefault
是否有一些 极端性能降级?
Does FirstOrDefault
has some extreme performance downgrade compared to FindAsync
?
实际上 Find{Async}
在本地缓存中未跟踪(包含)具有指定键的实体时使用 FirstOrDefault{Async}
。
所以 Find{Async}
的唯一好处是在多次使用时目标实体在本地缓存,因为它避免了数据库访问。
另一方面,Find{Async}
不支持预先加载(Include
/ ThenInclude
),通常用于短暂的上下文中,一次性寻找特定的键, 所以通常使用它没有真正的好处。
另一个与性能无关的区别是 Find{Async}
允许您定位新的未提交实体(状态 Added
),而所有其他方法查询数据库和 return 仅存在(或标记为 Deleted
)的实体。但它不能也不应用全局查询过滤器。
所以这真的取决于具体的用法。我会说在大多数常见情况下,您只需使用 FirstOrDefault{Async}
,而在极少数情况下 - Find{Async}
。我想大多数“存储库”示例都使用 Find{Async}
,因为它具有更紧凑的语法,而不是因为性能或其主要目的。
我在 ASP.NET Core API
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//...
modelBuilder.Entity<OneOfMyEntity>().HasQueryFilter(entity => !entity.IsDeleted);
modelBuilder.Entity<AnotherEntity>().HasQueryFilter(entity => !entity.IsDeleted);
}
现在这在我的 Repository
中封装了我的 DbContext
:
public async Task<List<TEntity>> GetAllExcludeDeleted()
{
return await _context.Set<TEntity>().ToListAsync();
}
public async Task<List<TEntity>> GetAll()
{
return await _context.Set<TEntity>().IgnoreQueryFilters().ToListAsync();
}
但是,当我在我的存储库上编写集成测试时,我意识到它不是 DbContext.FindAsync(int)
方法的解决方案:
public async Task<TEntity> GetById(int id)
{
return await _context.Set<TEntity>().FindAsync(id);
}
我的解决方案
我可以想象用 FirstOrDefault(e => !e.IsDeleted)
FindAsync(id)
来处理这个问题
真题
你们怎么看,有什么比用 Linq query
替换 FindAsync
更好的解决方案?与 FindAsync
相比,FirstOrDefault
是否有一些 极端性能降级?
Does
FirstOrDefault
has some extreme performance downgrade compared toFindAsync
?
实际上 Find{Async}
在本地缓存中未跟踪(包含)具有指定键的实体时使用 FirstOrDefault{Async}
。
所以 Find{Async}
的唯一好处是在多次使用时目标实体在本地缓存,因为它避免了数据库访问。
另一方面,Find{Async}
不支持预先加载(Include
/ ThenInclude
),通常用于短暂的上下文中,一次性寻找特定的键, 所以通常使用它没有真正的好处。
另一个与性能无关的区别是 Find{Async}
允许您定位新的未提交实体(状态 Added
),而所有其他方法查询数据库和 return 仅存在(或标记为 Deleted
)的实体。但它不能也不应用全局查询过滤器。
所以这真的取决于具体的用法。我会说在大多数常见情况下,您只需使用 FirstOrDefault{Async}
,而在极少数情况下 - Find{Async}
。我想大多数“存储库”示例都使用 Find{Async}
,因为它具有更紧凑的语法,而不是因为性能或其主要目的。