![](/img/trans.png)
[英]Dynamic LINQ OrderBy on IEnumerable<T> / IQueryable<T>
[英]Applying IEnumerable<'T>.OrderBy on a IQueryable<'T>
我在存储库中使用了一个自定义类型,可以帮助我显式表示查询选项,例如排序,分页等。
最初,界面如下所示:
public class IQueryAction<TEntity> {
IQueryable<TEntity> ApplyTo(IQueryable<T> entitity);
}
这样我就可以表示这样的排序:
public class SortingAction<TEntity, TSortKey> : IQueryAction<TEntity>
{
public Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> SortAction { get; }
public SortingAction(Expression<Func<TEntity, TSortKey>> sortExpression) {
SortAction = q => q.OrderBy(sortExpression);
}
public IQueryable<TEntity> ApplyTo(IQueryable<TEntity> query) {
return SortAction(query);
}
}
大多数时候,我使用实体框架,所以这不是问题。 但是,现在我需要为不提供查询提供程序( IQueryProvider
)的数据源实现IQueryAction<'T>
模型。 现在,我可以重构接口以使用IEnumerable<'T>
而不是IQueryable<'T>
并期望键选择器使用Func
委托代替lambda表达式 。
现在我的问题是:当将IQueryable<'T>
仅仅转换为IEnumerable<'T>
时,这是否会导致排序操作在内存中而不是在查询提供程序上运行? 因为我不会通过一个表情了,而是一个委托 ,怎么能查询供应商还知道想什么键我使用的查询? 并且,如果该方法不再起作用:根据IEnumerable<'T>
的基础类型,我该怎么做才能同时适合内存和查询提供程序中的排序?
public class MyEntity {
public int Id { get; set; }
public string Name { get; set }
}
// somewhere in code
var orderByName = new SortingAction<MyEntity, string>(x => x.Name);
myEntityRepository.GetAll(orderByName);
// ef repository impl
public IEnumerable<TEntity> GetAll(IQueryAction<TEntity> queryAction) {
return queryAction.ApplyTo(dbContext.Set<TEntity>()); // runs on the query provider
}
// misc repository impl not supporting IQueryable/IQueryProvider
public IEnumerable<TEntity> GetAll(IQueryAction<TEntity> queryAction) {
var result = someProvider.Sql("SELECT *")...
return queryAction.ApplyTo(result);
}
我要怎么做才能同时适合内存和查询提供程序中的排序
保持IQueryAction<TEntity>
,并使用AsQueryable
扩展将IEnumerable<T>
转换为IQueryable<T>
:
var list = new List<YourEntity> { /* ... */ };
var queryableList = list.AsQueryable();
sortingAction.ApplyTo(queryableList);
最终,这将对内存中的序列(如集合)进行内存中排序,并且它将针对“真”可查询对象对数据库发送查询。
当将IQueryable <'T>简单地转换为IEnumerable <'T>时,这是否会使排序操作在内存中而不是在查询提供程序上运行?
是的,因为您将绑定到在内存中进行排序的Enumerable
扩展方法。 那时底层的提供者是什么都没有关系。 Enumerable
扩展方法将枚举基础集合并将其“分类”在内存中。
根据
IEnumerable<T>
的基础类型,我该怎么做才能同时适合内存和查询提供程序?
客户端可以在调用方法之前调用ToQueryable()
。 如果基础集合已经是IQueryable<T>
则仅对输入进行强制转换; 否则,将适配器放在IEnumerable
顶部,以使IQueryable
方法适应IEnumerable
方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.