我正在使用Entity Framework,我有一个custum IQueryProvider。我使用Execute方法,以便我可以在执行后修改查询的结果(POCO)。我想对收藏品做同样的事情。问题是只对单个结果调用Execute方法。
如MSDN所述:
Execute方法执行返回单个值的查询 (而不是可枚举的值序列)。表达树那个 表示返回可枚举结果的查询 它们的相关IQueryable对象被枚举。
还有另一种方法可以实现我想要的错过吗?
我知道我可以在存储库中编写一个特定的方法,或者我想将其应用于所有可能的查询。
答案 0 :(得分:1)
确实,实际的签名是:
public object Execute(Expression expression)
public TResult Execute<TResult>(Expression expression)
然而,并不意味着 TResult永远是一个元素!它是期望从表达式返回的类型。
另请注意,TResult
上有无约束,甚至不是'class'或'new()'。
如果您的表达式具有单一结果,则TResult为MyObject
,例如.FirstOrDefault()
。但是,当您double
超过查询时,TResult也可以是.Avg()
,当您的查询为普通IEnumerable<MyObject>
时,它也可以是.Select.Where
。
证明(*) - 我刚刚在我的Execute()实现中设置了一个断点,并且我用Watches检查了它:
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
,所以它至少需要四次重载:)
Proof标有(*),因为我的IQueryProvider代码中有一个小错误/特征,它掩盖了LINQ的真实行为。
LINQ确实仅针对奇异案例调用通用Execute。这是一种快捷方式,优化。
对于所有其他情况,它...... 根本不会调用Execute()
对于所有其他情况,LINQ在您的自定义.GetEnumerator
实现上调用IQueryable<>
,所发生的事情由......在您那里写的内容决定。我的意思是,假设您实际提供了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 = Single Element”的情况,因为你写的是这样的东西:
public IEnumerator<TOut> GetEnumerator()
{
return Provider.Execute<TOut>( this.Expression ).GetEnumerator();
}
这真的无法选择您的Execute实现,并且必须返回单个元素。恕我直言,这只是你的代码中的一个错误。你可以像我上面的例子那样做,或者你可以简单地使用无类型的执行:
public System.Collections.IEnumerator GetEnumerator()
{
return ((IEnumerable)Provider.Execute( this.Expression )).GetEnumerator();
}
public IEnumerator<TOut> GetEnumerator()
{
return ((IEnumerable<TOut>)Provider.Execute( this.Expression )).GetEnumerator();
}
当然,您的Execute实现必须确保为此类查询返回正确的IEnumebles!
答案 1 :(得分:0)
表示返回可枚举结果的查询的表达式树在枚举其关联的IQueryable对象时执行。
我建议枚举您的查询:
foreach(T t in query)
{
CustomModification(t);
}
您的IQueryProvider必须实施CreateQuery<T>
。您可以选择生成的IQueryable的实现。如果您希望IQueryable在枚举时对每一行执行某些操作,则可以编写该实现。
答案 2 :(得分:-1)
最后的答案是,这是不可能的。