2012-01-05 37 views
2

我正在使用实体框架,并且我有一个custum IQueryProvider。我使用Execute方法,以便可以在执行is后修改查询的结果(POCO)。我想为集合做同样的事情。问题在于Execute方法仅针对单个结果调用。如何拦截IQueryProvider查询的结果(除单个结果)

如上描述MSDN:

Execute方法执行返回单个值 (而不是值的枚举序列)的查询。 表示返回可枚举结果的查询的表达式树会在枚举其关联的IQueryable对象时执行 。

有没有另一种方法可以完成我想要的东西,我错过了?

我知道我可以在存储库或任何其他地方写一个特定的方法,但我想将其应用于所有可能的查询。

回答

-1

最终的答案是,这是不可能的。

+0

我认为你错了,请查看我的答案。 – quetzalcoatl 2013-02-18 12:00:23

0

表示返回枚举结果的查询的表达式树在枚举其关联的IQueryable对象时执行。

我建议你列举查询:

foreach(T t in query) 
{ 
    CustomModification(t); 
} 

你IQueryProvider必须实现CreateQuery<T>。您可以选择生成的IQueryable的实现。如果你希望IQueryable在枚举时为每一行做一些事情,你可以编写该实现。

+0

是的,如果它是ONE查询,这将工作。但是我正在构建一个框架,并且我没有一个可以枚举查询的地方。我希望为每个查询都坐在Entity Framework之上。正如我所说,我想要的IQueryProvider的Execute方法的确切等价物,但枚举结果。 – W3Max 2012-01-09 19:04:07

1

这是真实的,实际的签名是:

public object Execute(Expression expression) 
public TResult Execute<TResult>(Expression expression) 

然而,并不意味着该TResult将永远是一个单一的元素!这是预期从表达式返回的类型。

此外,请注意,没有限制而不是TResult,甚至没有'class'或'new()'。

TResult是一个MyObject当你的表达是单数结果,如.FirstOrDefault()。但是,当您在查询上使用.Avg()时,TResult也可以是double,并且当查询是普通的.Select.Where时,也可以是IEnumerable<MyObject>

证明(*) - 我刚刚设置断点我的执行()里面执行,我已经与手表检查它:

typeof(TResult).FullName "System.Collections.Generic.IEnumerable`1[[xxxxxx,xxxxx]]" 
expression.Type.FullName "System.Linq.IQueryable`1[[xxxxxx,xxxxx]]" 

我承认三个重载,一个object,一个TResult和一个IEnumerable<TResult>可能会更具可读性。我认为他们没有把它们中的三个作为未来接口的可扩展性。我可以想象,将来他们会想出比IEnumerable更强大的东西,然后他们需要添加另一个过载等等。用简单的这个接口可以处理任何类型的

哦,看,我们现在也有IQueryable除了IEnumerable,所以它需要至少四个重载:)

证明是标有(*),因为我曾在一个小bug /功能我的IQueryProvider的代码掩盖了LINQ的真实行为。

LINQ确实只为单数情况调用通用执行。这是一个快捷方式,优化

对于所有其他情况下,...... 不调用execute()它在所有

对于所有其他情况下,LINQ上的自定义IQueryable<>实现调用.GetEnumerator,出现这种情况是什么决定通过..只是你写在那里。我的意思是,假设你实际提供了IQueryable的自定义实现。如果你不这么做,那会很奇怪 - 总共只有15行,与自定义提供程序的长度相比没什么差别。

在我从拿到“证明”的项目,我的实现是这样的:

public System.Collections.IEnumerator GetEnumerator() 
{ 
    return Provider.Execute<IEnumerable>(this.Expression).GetEnumerator(); 
} 

public IEnumerator<TOut> GetEnumerator() 
{ 
    return Provider.Execute<IEnumerable<TOut>>(this.Expression).GetEnumerator(); 
} 
当然

,其中之一是由于名称冲突明确。请注意,为了获取枚举器,我实际上用明确声明的TResult调用Execute。这就是为什么在我的“证据”中出现这些类型的原因。

我认为你看到“TResult =单元素”的情况下,因为你写的即是这样的:

public IEnumerator<TOut> GetEnumerator() 
{ 
    return Provider.Execute<TOut>(this.Expression).GetEnumerator(); 
} 

这实际上使你执行不执行选择,并且必须返回单个元素。恕我直言,这只是你的代码中的一个错误。你可以在我的例子都做到了像上面,或者你可以简单地使用非类型化的执行:

public System.Collections.IEnumerator GetEnumerator() 
{ 
    return ((IEnumerable)Provider.Execute(this.Expression)).GetEnumerator(); 
} 

public IEnumerator<TOut> GetEnumerator() 
{ 
    return ((IEnumerable<TOut>)Provider.Execute(this.Expression)).GetEnumerator(); 
} 

当然,你的执行,执行必须确保返回正确IEnumerables这样的查询!