1

我正在尝试使用 Linq to Entities 对 asp.net OData 服务公开的实体应用额外的服务器端过滤。

到目前为止一切都很好,但是我为过滤器构建的 Linq 查询有时会变得很长,从而导致 StackOverflowException。

作为一种解决方法,我想在一个单独的线程中执行查询,为该线程提供更大的堆栈大小限制。为了实现这一点,我实现了 IQueryable 和 IQueryProvider 包装器,这样当调用 IQueryable 的 Execute 方法时,它将在单独的线程中执行。

为了保持简单并专注于我的问题,我将在以下代码示例中省略线程部分,因为这不是这里的问题。

以下是代码的相关部分:

public class MyQueryable<T> : IQueryable<T> {
    private IQueryable<T> _Inner { get; set; }
    private IQueryProvider _Provider { get; set; }

    public MyQueryable(IQueryable<T> inner) {
        _Inner = inner;
        _Provider = new MyQueryProvider(inner.Provider);
    }

    public Type ElementType {
        get { return _Inner.ElementType; }
    }

    public Expression Expression {
        get { return _Inner.Expression; }
    }

    public IQueryProvider {
        get { return _Provider; }
    }

    /* ... Implementations of GetEnumerator ... */
}

public class MyQueryProvider : IQueryProvider {
    private IQueryProvider _Inner { get; set; }

    public MyQueryProvider(IQueryProvider inner) {
        _Inner = inner;
    }

    public IQueryable<T> CreateQuery<T>(Expression expression) {
        return new MyQueryable<T>(_Inner.CreateQuery<T>(expression));
    }

    public T Execute<T>(Expression expression) {
        // The problem occurs on the following line.
        return _Inner.Execute<T>(expression);
    }

    /* ... Implementation of the non-generic versions of CreateQuery, Execute ... */
}

当我运行它时,我在 MyQueryProvider.Execute 方法中得到一个 InvalidOperationException:

Cannot compare elements of type 'System.Collections.Generic.ICollection`1'.
Only primitive types (such as Int32, String, and Guid) and entity types are supported.

这就是我构建传递给 MyQueryable 的原始 IQueryable 的方式:我从实体上下文中获取 DbSet,对其应用 OData 过滤器查询选项,然后调用 Count()。类似于以下内容:

((odataQueryOptions.Filter.ApplyTo(
    context.Entities.AsQueryable(), new ODataQuerySettings()))
as IQueryable<Entity>).Count()

我部分确定问题在于 odata 过滤器查询选项包含嵌套的“任何”过滤器,例如:

Entities/$filter=RelatedEntities/any(entity: (entity/ID eq 1))

这会向 IQueryable 的 Where 表达式添加检查 RelatedEntities 集合是否为空。据推测,此检查是导致上述异常的原因。

我无法理解的是,为什么当我尝试将 Execute 方法的执行从 MyQueryable.Execute 方法委托给它时,原始 IQueryable 会失败,但是当我直接使用原始 IQueryable 时,它​​一切正常。

对此的任何帮助将不胜感激。提前致谢。

4

0 回答 0