EF Core 2+ - 使用通用存储库进行预加载
EF Core 2+ - Eager loading using generic repository
我的BaseRespository
是这样的:
public abstract class BaseRespository<TEntity, TContext> : IBaseRepository<TEntity>
where TEntity : class
where TContext : DbContext
{
private readonly TContext _context;
protected BaseRespository(TContext context)
{
_context = context;
}
public async Task<TEntity> GetByCondition(Expression<Func<TEntity, bool>> predicate)
{
return await _context.Set<TEntity>().Where(predicate).FirstOrDefaultAsync();
}
}
然后我像这样访问 GetByCondition
方法:
public async Task<Tips> GetTipBySlug(string slug)
{
Expression<Func<Tips, bool>> predicate = (t) => t.Slug == slug &&
t.Status == (int)LU_Status.active &&
t.User.Status == (int)LU_Status.active;
return await _tipRepository.GetByCondition(predicate);
}
我想将 EF Core 的 Include
和 ThenInclude
与谓词一起使用(这正是我的愿望),如下所示:
public async Task<Tips> GetTipBySlug(string slug)
{
Expression<Func<Tips, bool>> whereExpr = (t) => t.Include(t=>t.User).ThenInclude(u=>u.UserImages)
t.Slug == slug &&
t.Status == (int)LU_Status.active &&
t.User.Status == (int)LU_Status.active;
return await _tipRepository.GetByCondition(whereExpr);
}
如何使用 EF CORE 2 及更高版本将所需的 t.Include(t=>t.User).ThenInclude(u=>u.UserImages)
添加到谓词?
即使这不需要将您的逻辑拆分到多个存储库参数中也能奏效,您真的更愿意写
Expression<Func<Tips, bool>> whereExpr = (t) => t.Include(t=>t.User).ThenInclude(u=>u.UserImages)
t.Slug == slug &&
t.Status == (int)LU_Status.active &&
t.User.Status == (int)LU_Status.active;
return await _tipRepository.GetByCondition(whereExpr);
关于 EF 的设计使用方式:
var q = _tipRepository.Set<Tips>()
.Include(t=>t.User)
.ThenInclude(u=>u.UserImages)
.Where(t => t.Status == (int)LU_Status.active)
.Where(t => t.User.Status == (int)LU_Status.active);
return await q.FirstOrDefaultAsync();
为什么要创建 Expression<Func<Tips,bool>>
而不是 IQueryabe<T>
。它 nothing 与存储库是否 "generic" 相关,everything 与您想如何编写查询有关。查询由存储库的 消费者 编写。不在存储库中或存储库中(除非您希望跨消费者重复使用查询)。
这种设计的疯狂之处在于它允许存储库的消费者指定查询。它只是迫使他们通过笨重的定制 API.
来做到这一点
你可以这样写:
public async Task<TEntity> GetByCondition<TEntity>(Expression<Func<TEntity, bool>> predicate, Func<DbSet<TEntity>, IQueryable<TEntity>> baseQuery = null) where TEntity : class
{
IQueryable<TEntity> q = Set<TEntity>();
if (baseQuery != null)
{
q = baseQuery(Set<TEntity>());
}
return await q.Where(predicate).FirstOrDefaultAsync();
}
你不需要那个表达式,因为 Include
没有延迟。它是returns一个IIncludableQueryable的函数,所以它是一个查询转换函数。
然后:
public async Task<Tips> GetTipBySlug(string slug)
{
Expression<Func<Tips, bool>> whereExpr = (t) => t.Slug == slug &&
t.Status ==1 &&
t.User.Status == 1;
return await GetByCondition(whereExpr, s => s.Include(t => t.User).ThenInclude(u => u.UserImages)) ;
}
我的BaseRespository
是这样的:
public abstract class BaseRespository<TEntity, TContext> : IBaseRepository<TEntity>
where TEntity : class
where TContext : DbContext
{
private readonly TContext _context;
protected BaseRespository(TContext context)
{
_context = context;
}
public async Task<TEntity> GetByCondition(Expression<Func<TEntity, bool>> predicate)
{
return await _context.Set<TEntity>().Where(predicate).FirstOrDefaultAsync();
}
}
然后我像这样访问 GetByCondition
方法:
public async Task<Tips> GetTipBySlug(string slug)
{
Expression<Func<Tips, bool>> predicate = (t) => t.Slug == slug &&
t.Status == (int)LU_Status.active &&
t.User.Status == (int)LU_Status.active;
return await _tipRepository.GetByCondition(predicate);
}
我想将 EF Core 的 Include
和 ThenInclude
与谓词一起使用(这正是我的愿望),如下所示:
public async Task<Tips> GetTipBySlug(string slug)
{
Expression<Func<Tips, bool>> whereExpr = (t) => t.Include(t=>t.User).ThenInclude(u=>u.UserImages)
t.Slug == slug &&
t.Status == (int)LU_Status.active &&
t.User.Status == (int)LU_Status.active;
return await _tipRepository.GetByCondition(whereExpr);
}
如何使用 EF CORE 2 及更高版本将所需的 t.Include(t=>t.User).ThenInclude(u=>u.UserImages)
添加到谓词?
即使这不需要将您的逻辑拆分到多个存储库参数中也能奏效,您真的更愿意写
Expression<Func<Tips, bool>> whereExpr = (t) => t.Include(t=>t.User).ThenInclude(u=>u.UserImages)
t.Slug == slug &&
t.Status == (int)LU_Status.active &&
t.User.Status == (int)LU_Status.active;
return await _tipRepository.GetByCondition(whereExpr);
关于 EF 的设计使用方式:
var q = _tipRepository.Set<Tips>()
.Include(t=>t.User)
.ThenInclude(u=>u.UserImages)
.Where(t => t.Status == (int)LU_Status.active)
.Where(t => t.User.Status == (int)LU_Status.active);
return await q.FirstOrDefaultAsync();
为什么要创建 Expression<Func<Tips,bool>>
而不是 IQueryabe<T>
。它 nothing 与存储库是否 "generic" 相关,everything 与您想如何编写查询有关。查询由存储库的 消费者 编写。不在存储库中或存储库中(除非您希望跨消费者重复使用查询)。
这种设计的疯狂之处在于它允许存储库的消费者指定查询。它只是迫使他们通过笨重的定制 API.
来做到这一点你可以这样写:
public async Task<TEntity> GetByCondition<TEntity>(Expression<Func<TEntity, bool>> predicate, Func<DbSet<TEntity>, IQueryable<TEntity>> baseQuery = null) where TEntity : class
{
IQueryable<TEntity> q = Set<TEntity>();
if (baseQuery != null)
{
q = baseQuery(Set<TEntity>());
}
return await q.Where(predicate).FirstOrDefaultAsync();
}
你不需要那个表达式,因为 Include
没有延迟。它是returns一个IIncludableQueryable的函数,所以它是一个查询转换函数。
然后:
public async Task<Tips> GetTipBySlug(string slug)
{
Expression<Func<Tips, bool>> whereExpr = (t) => t.Slug == slug &&
t.Status ==1 &&
t.User.Status == 1;
return await GetByCondition(whereExpr, s => s.Include(t => t.User).ThenInclude(u => u.UserImages)) ;
}