.NET 存储库模式通用查询方法
.NET Repository pattern generic Query Methodology
我正在使用存储库模式,我有一个基本存储库,我使用 Entity Framework 和网络 api;
我的问题是我想让我的客户能够动态查询任何数据;类似于 Dynamics CRM 中使用的查询表达式和 fetch xml;
我尝试了规范模式,但这还不够,因为我想让客户端代码对具有不同列的数据进行排序,例如Name asc Address desc 并且允许对返回结果进行分页;所以我的方法要求是
- 不依赖于 ORM 技术的通用过滤器
以后改变Entity Framework
- 通用排序方法;允许多个排序列,例如
名称 asc 地址 desc
- 客户端确定返回的列或所有列,例如
列设置为 "Address, Name and Id" 或返回整条记录
- 允许分页,例如页面索引和页面大小
- 支持返回记录数的阈值尽可能大
结果可能会影响性能
这是我最初的方法,但我不知道它是否更好
IList<TEntity> AllMatching(ISpecification<TEntity> specification = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
IList<Expression<Func<TEntity, object>>> includes = null,
int? pageIndex = null, int? pageCount = null);
您可以开始这样做了:
public IQueryable<TEntity> Select(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
IList<Expression<Func<TEntity, object>>> includes = null,
int? page = null,
int? pageSize = null)
{
IQueryable<TEntity> query = _dbSet;
if (includes != null)
{
query = includes.Aggregate(query, (current, include) => current.Include(include));
}
if (orderBy != null)
{
query = orderBy(query);
}
if (filter != null)
{
query = query.AsExpandable().Where(filter);
}
if (page != null && pageSize != null)
{
query = query.Skip((page.Value - 1)*pageSize.Value).Take(pageSize.Value);
}
return query;
}
如您所见,它几乎可以满足您的所有需求,因此,如果您想在 Repository
实现中执行相同的操作,则必须使用 LinqKit nuget 包。
如果您想要 select 特定列,您可以创建另一种方法,如下所示:
IEnumerable<TResult> AllMatching<TResult>(
Expression<Func<TEntity, TResult>> columns,
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
IList<Expression<Func<TEntity, object>>> includes = null,
int? pageIndex = null,
int? pageCount = null)
{
var query=Select(filter,orderby,includes,page,pageSize);
return query.Select(columns);
}
我正在使用存储库模式,我有一个基本存储库,我使用 Entity Framework 和网络 api; 我的问题是我想让我的客户能够动态查询任何数据;类似于 Dynamics CRM 中使用的查询表达式和 fetch xml; 我尝试了规范模式,但这还不够,因为我想让客户端代码对具有不同列的数据进行排序,例如Name asc Address desc 并且允许对返回结果进行分页;所以我的方法要求是
- 不依赖于 ORM 技术的通用过滤器 以后改变Entity Framework
- 通用排序方法;允许多个排序列,例如 名称 asc 地址 desc
- 客户端确定返回的列或所有列,例如 列设置为 "Address, Name and Id" 或返回整条记录
- 允许分页,例如页面索引和页面大小
- 支持返回记录数的阈值尽可能大 结果可能会影响性能
这是我最初的方法,但我不知道它是否更好
IList<TEntity> AllMatching(ISpecification<TEntity> specification = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
IList<Expression<Func<TEntity, object>>> includes = null,
int? pageIndex = null, int? pageCount = null);
您可以开始这样做了:
public IQueryable<TEntity> Select(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
IList<Expression<Func<TEntity, object>>> includes = null,
int? page = null,
int? pageSize = null)
{
IQueryable<TEntity> query = _dbSet;
if (includes != null)
{
query = includes.Aggregate(query, (current, include) => current.Include(include));
}
if (orderBy != null)
{
query = orderBy(query);
}
if (filter != null)
{
query = query.AsExpandable().Where(filter);
}
if (page != null && pageSize != null)
{
query = query.Skip((page.Value - 1)*pageSize.Value).Take(pageSize.Value);
}
return query;
}
如您所见,它几乎可以满足您的所有需求,因此,如果您想在 Repository
实现中执行相同的操作,则必须使用 LinqKit nuget 包。
如果您想要 select 特定列,您可以创建另一种方法,如下所示:
IEnumerable<TResult> AllMatching<TResult>(
Expression<Func<TEntity, TResult>> columns,
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
IList<Expression<Func<TEntity, object>>> includes = null,
int? pageIndex = null,
int? pageCount = null)
{
var query=Select(filter,orderby,includes,page,pageSize);
return query.Select(columns);
}