我编写了一个自定义 IQueryProvider 类,该类接受一个表达式并针对 SQL 数据库对其进行分析(我知道我可以使用 Linq2Sql,但我需要进行一些修改和调整,不幸的是,这使得 Linq2Sql 不适合)。该类将识别并处理标记的属性(使用属性),但我希望能够将表达式传递给 LinqToObject 提供程序并允许它过滤之后的结果。
例如,假设我有以下 linq 表达式:
var parents=Context.Parents
.Where(parent=>parent.Name.Contains("T") && parent.Age>18);
Parent类是一个自定义类,实现了IQueryProvider和IQueryable接口,但是只有Age属性被标记为检索,所以会处理Age属性,但是Name属性因为没有被标记而被忽略。在我处理完 Age 属性后,我想将整个表达式传递给 LinqToObjects 进行处理和过滤,但我不知道如何。
NB 它不需要删除表达式的 Age 子句,因为即使在我处理它之后结果也是一样的,所以我总是能够将整个表达式发送到 LinqToObjects。
我已经尝试了以下代码,但它似乎不起作用:
IEnumerator IEnumerable.GetEnumerator() {
if(this.expression != null && !this.isEnumerating) {
this.isEnumerating = true;
var queryable=this.ToList().AsQueryable();
var query = queryable.Provider.CreateQuery(this.expression);
return query.GetEnumerator();
}
return this;
}
this.isEnumerating 只是一个布尔标志,用于防止递归。
this.expression 包含以下内容:
{value(namespace.Parents`1[namespace.Child]).Where(parent => ((parent.Name.EndsWith("T") AndAlso parent.Name.StartsWith("M")) AndAlso (parent.Test > 0)))}
当我单步执行代码时,尽管将结果转换为列表,但它仍然使用我的自定义类进行查询。所以我想,因为类 Parent 位于表达式的开头,它仍在将查询路由回我的提供程序,所以我尝试将 this.expression 设置为方法调用的 Argument[1] ,所以它是这样的:
{parent => ((parent.Name.EndsWith("T") AndAlso parent.Name.StartsWith("M")) AndAlso (parent.Test > 0))}
对我来说看起来更像它,但是,每当我将它传递给 CreateQuery 函数时,我都会收到此错误“参数表达式无效”。
表达式的节点类型现在是 'Quote' 而不是 'Call' 并且方法为 null。我怀疑我只需要以某种方式使这个表达式成为调用表达式,它就会起作用,但我不知道该怎么做。
请记住,此表达式是 where 子句,但它可能是任何类型的表达式,我不希望在将表达式传递给 List 查询提供程序之前尝试分析表达式以查看它是什么类型。
也许有一种方法可以将原始表达式的 Parent 类剥离或替换为列表提供程序类,但仍使其处于可以作为表达式传入列表提供程序的状态,而不管表达式的类型如何?
对此的任何帮助将不胜感激!