繁体   English   中英

将IEnumerable <'T> .OrderBy应用于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM