Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 依赖LinqToObject的自定义IQueryProvider_C#_Linq To Objects_Iqueryable - Fatal编程技术网

C# 依赖LinqToObject的自定义IQueryProvider

C# 依赖LinqToObject的自定义IQueryProvider,c#,linq-to-objects,iqueryable,C#,Linq To Objects,Iqueryable,我已经编写了一个定制的IQueryProvider类,它接受一个表达式并根据SQL数据库对其进行分析(我知道我可以使用Linq2Sql,但我需要进行一些修改和调整,不幸的是,这些修改和调整使Linq2Sql不适用)。该类将识别已标记的属性(使用属性)并对其执行某些操作,但任何未标记的属性我希望能够将表达式传递给LinqToObject提供程序,并允许它在之后过滤结果 例如,假设我有以下linq表达式: var parents=Context.Parents .Where(parent=&

我已经编写了一个定制的IQueryProvider类,它接受一个表达式并根据SQL数据库对其进行分析(我知道我可以使用Linq2Sql,但我需要进行一些修改和调整,不幸的是,这些修改和调整使Linq2Sql不适用)。该类将识别已标记的属性(使用属性)并对其执行某些操作,但任何未标记的属性我希望能够将表达式传递给LinqToObject提供程序,并允许它在之后过滤结果

例如,假设我有以下linq表达式:

var parents=Context.Parents
    .Where(parent=>parent.Name.Contains("T") && parent.Age>18);
Parents类是实现IQueryProvider和IQueryable接口的自定义类,但只有Age属性被标记为可检索,因此将处理Age属性,但忽略Name属性,因为它未被标记。处理完Age属性后,我想将整个表达式传递给LinqToObject进行处理和筛选,但我不知道如何处理

注意,它不需要删除表达式的Age子句,因为即使在我处理它之后,结果也会相同,所以我始终能够将整个表达式发送到LinqToObject

我尝试了以下代码,但似乎不起作用:

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;
}
isEnumerating只是一个布尔标志集,用于防止递归

此.expression包含以下内容:

{value(namespace.Parents`1[namespace.Child]).Where(parent => ((parent.Name.EndsWith("T") AndAlso parent.Name.StartsWith("M")) AndAlso (parent.Test > 0)))}
当我逐步浏览代码时,尽管将结果转换为列表,但它仍然使用我的自定义类进行查询。因此,我认为,由于类父级位于表达式的开头,它仍在将查询路由回我的提供程序,因此我尝试将this.expression设置为方法调用的参数[1],如下所示:

{parent => ((parent.Name.EndsWith("T") AndAlso parent.Name.StartsWith("M")) AndAlso (parent.Test > 0))}
这对我来说更像是这样,但是,每当我将其传递到CreateQuery函数时,就会出现这样的错误“参数表达式无效”

表达式的节点类型现在是'Quote'而不是'Call',方法为null。我怀疑我只需要以某种方式使这个表达式成为调用表达式,它就会工作,但我不确定如何工作

请记住,此表达式是where子句,但它可能是任何类型的表达式,我不希望在将其传递给列表查询提供程序之前尝试分析表达式以查看其类型

也许有一种方法可以剥离原始表达式的父类或将其替换为列表提供程序类,但仍然使其处于可以作为表达式传递到列表提供程序的状态,而不管表达式的类型如何

在此方面的任何帮助都将不胜感激

你离得太近了

我的目标是避免“复制”整个令人麻木的复杂SQL对象表达式功能集。您让我走上了正确的道路(谢谢!)以下是如何在自定义IQueryable中将SQL背驮到对象:

public IEnumerator<T> GetEnumerator() {

    // For my case (a custom object-oriented database engine) I still 
    // have an IQueryProvider which builds a "subset" of objects each populated 
    // with only "required" fields, as extracted from the expression. IDs, 
    // dates, particular strings, what have you. This is "cheap" because it 
    // has an indexing system as well.

    var en = ((IEnumerable<T>)this.provider.Execute(this.expression));

    // Copy your internal objects into a list.

    var ar = new List<T>(en);
    var queryable = ar.AsQueryable<T>();

    // This is where we went wrong:
    // queryable.Provider.CreateQuery(this.expression);
    // We can't re-reference the original expression because it will loop 
    // right back on our custom IQueryable<>. Instead, swap out the first 
    // argument with the List's queryable:

    var mc = (MethodCallExpression)this.expression;
    var exp = Expression.Call(mc.Method, 
                    Expression.Constant(queryable), 
                    mc.Arguments[1]);


    // Now the CLR can do all of the heavy lifting
    var query = queryable.Provider.CreateQuery<T>(exp);
    return query.GetEnumerator();
}
public IEnumerator GetEnumerator(){
//对于我的案例(一个定制的面向对象数据库引擎),我仍然
//有一个IQueryProvider,它构建每个填充对象的“子集”
//仅包含从表达式.IDs中提取的“必需”字段,
//日期,特别的字符串,你有什么。这是“便宜”的,因为它
//也有一个索引系统。
var en=((IEnumerable)this.provider.Execute(this.expression));
//将内部对象复制到列表中。
var ar=新列表(en);
var queryable=ar.AsQueryable();
//这就是我们出错的地方:
//queryable.Provider.CreateQuery(this.expression);
//无法重新引用原始表达式,因为它将循环
//回到我们的定制IQueryable,换掉第一个
//具有列表的可查询项的参数:
var mc=(MethodCallExpression)this.expression;
var exp=Expression.Call(mc.Method,
表达式.常量(可查询),
mc.论点[1];
//现在,CLR可以完成所有的繁重工作
var query=queryable.Provider.CreateQuery(exp);
返回query.GetEnumerator();
}

真不敢相信,我花了3天的时间才弄明白如何避免在LINQ到对象查询上重新发明轮子。

所以,您希望根据Linq2Db计算表达式的一部分,然后在从DB检索结果后,根据Linq2Objects计算表达式的一部分?哈哈,我写了所有这些,你用一句话来概括……噢!你是对的,这就是我想要做的,但我不一定只需要表达式的一部分就可以了,如果它能让它变得更简单的话,一切都可以了;否则,我会认为您需要检查表达式并将其拆分为两个表达式;将其传递给
IQueryable
,然后在完全枚举该集合后,编译第二个表达式并将其传递给来自Linq的
Where
调用。听起来比我想的要简单。不过,你需要调用某种聚合器,例如(
ToList
),以确保从数据库中提取结果。