冻结linq IQueryable(作为ToList().AsQueryable()会这样做)

Jac*_*ers 6 c# linq entity-framework odata

有没有办法冻结,IQueryable以便在命中数据库时不会向查询添加额外的连接?例如,我可以做一个.ToList()冻结查询,但这会产生性能影响,因为我所做的任何过滤都在中间层,而我在数据库服务器上预过滤没有任何性能提升?


为清晰起见编辑:

我有一个OData服务,它返回一个IQueryable客户端可以根据需要过滤/排序/项目.我只想阻止他们提取更多数据.我可以这样做ToList().AsQueryable(),但这会失去lazyLoading的优势,并且随之而来的是允许客户端过滤请求的全部目的.

我看到的一个选项是设置:EnableQueryAttribute.AllowedQueryOptions排除Expand,但即使我的初始查询已经扩展,客户端仍然无法选择这些部分.

Luc*_*tti 2

我假设你实际上有一个IQueryable<T>而不是一个IQueryable

如果您不希望客户端访问所有IQueryable<T>方法,请不要返回IQueryable<T>. 由于您希望它们只能过滤/排序/项目,因此创建一个包含IQueryable<T>但仅公开所需方法的对象,并使用它:

public interface IDataResult<T>
{
    IDataResult<T> FilterBy(Expression<Func<T, bool>> predicate);

    IDataResult<TResult> ProjectTo<TResult>(Expression<Func<T, TResult>> predicate);

    IDataResult<T> SortBy<TKey>(Expression<Func<T, TKey>> keySelector);

    IDataResult<T> SortByDescending<TKey>(Expression<Func<T, TKey>> keySelector);

    List<T> ToList();

    IEnumerable<T> AsEnumerable();
}

public class DataResult<T> : IDataResult<T>
{
    private IQueryable<T> Query { get; set; }

    public DataResult(IQueryable<T> originalQuery)
    {
        this.Query = originalQuery;
    }

    public IDataResult<T> FilterBy(Expression<Func<T, bool>> predicate)
    {
        return new DataResult<T>(this.Query.Where(predicate));
    }

    public IDataResult<T> SortBy<TKey>(Expression<Func<T, TKey>> keySelector)
    {
        return new DataResult<T>(this.Query.OrderBy(keySelector));
    }

    public IDataResult<T> SortByDescending<TKey>(Expression<Func<T, TKey>> keySelector)
    {
        return new DataResult<T>(this.Query.OrderByDescending(keySelector));
    }

    public IDataResult<TResult> ProjectTo<TResult>(Expression<Func<T, TResult>> predicate)
    {
        return new DataResult<TResult>(this.Query.Select(predicate));
    }

    public List<T> ToList()
    {
        return this.Query.ToList();
    }

    public IEnumerable<T> AsEnumerable()
    {
        return this.Query.AsEnumerable();
    }
} 
Run Code Online (Sandbox Code Playgroud)

这样您还可以防止 EF 和 DB 相关的依赖关系在您的应用程序中蔓延。对方法的任何更改IQueryable<T>都将包含在此类中,而不是散布到各处。