【问题标题】:Casting LINQ expression throws "Internal .NET Framework Data Provider error 1025."转换 LINQ 表达式会引发“内部 .NET Framework 数据提供程序错误 1025”。
【发布时间】:2014-07-15 18:12:13
【问题描述】:

以下代码:

model.Items = dbQuery.Select(c => new Item {
    Total = c.Items.Count((Func<Item, bool>)(t => t.Amount.HasValue))
}).ToArray();

抛出以下异常:

内部 .NET Framework 数据提供程序错误 1025。

但是减去演员表的确切代码是有效的:

model.Items = dbQuery.Select(c => new Item {
    Total = c.Items.Count(t => t.Amount.HasValue)
}).ToArray();

注意:dbQuery 只是一个 EF ObjectQuery

Count() 的预期类型是 Func&lt;Item, bool&gt;,ReSharper 甚至验证了它们是同一类型,因为它会使强制转换为灰色,这表明它不是必需的,并且它们在功能上是等效的。

但是,异常证明它们,实际上在功能上是等价的。

另外,我确实看到了this related question/answer,但Count()(在这种情况下,无论如何)不会接受Expression&lt;Func&lt;Item bool&gt;&gt;,所以这对我不起作用。

【问题讨论】:

  • 那么您为什么要尝试添加一些设计为无用的东西,但这会导致您的代码根本无法工作。如果您这样做时会感到疼痛,请不要这样做。
  • 您是否尝试转换为 Espression&lt;Func&lt;Item,bool&gt;&gt;
  • @AlexanderGalkin 他在问题中回答了这个问题。
  • @Servy 为了简单起见,我试图从细节中抽象出实际问题。但这归结为这样一个事实,即我试图在我的(更复杂的)表达式中重用逻辑,并且将此逻辑存储在 Func&lt;Item, bool&gt; 中不起作用。但是如果我可以让上面的代码工作,那么我可以解决我更复杂的实际问题。
  • @JeradRose 不,你不能。如果查询提供程序足够健壮,可以期待它,那么您提供的代码理论上是可以工作的。实际上,从表达式中提取代码并将其存储在委托中实际上会从表达式中删除信息,使得查询提供者不可能访问信息,无论其编写得多么健壮。当然,这并不是说不可能将一个表达式分成多个表达式,因为它是,你根本无法通过将代码放在委托中来做到这一点。

标签: c# linq entity-framework


【解决方案1】:

您希望“将 [the] 表达式存储在变量中,以供重用,并将其传递给 Count()”。如果Expression 可以转换为 SQL,这是 100% 可能的。这里的问题是你引入了一些不能被翻译成SQL的东西。这种情况下的特殊问题是演员被转换为Expression.Convert。您的类型绝对没有在 SQL 中表示,所以这将无法执行。将两者都插入 LINQPad 并检查 IL 以查看差异。

正如您链接到的其他相关问题/答案所暗示的那样,您需要将谓词作为 Expression 而不是 Func 传递(如何完成工作而不是指向执行工作的代码中的位置)。正如您所指出的,问题是Count 方法不采用Expression,但这很容易通过使用AsQueryable() 解决,这将为您提供采用ExpressionIQueryable 扩展方法。

这应该没有问题执行:

Expression<Func<Item,bool>> predicate = i => i.Amount.HasValue;

model.Items = dbQuery.Select(c => new Item {
    Total = c.Items.AsQueryable().Count(predicate)
}).ToArray();

【讨论】:

  • 很确定查询提供者不知道如何处理AsQueryable 调用。
  • 我也不认为它会,但它会(至少在 EF6 -> MSSQL2008 中)。感谢评论者对 OP 链接到的问题的接受答案。
  • 并且它会生成相应的 SQL 代码,而不仅仅是在应用程序端进行工作?
  • 是的,也确认了。
【解决方案2】:

问题在于数据提供者无法将该 LINQ 表达式转换为 SQL 语句。在一个不起作用的情况下,Count 被传递给一个方法的委托。将其视为将指针传递给如下方法:

private static bool MyFunction(Item item)
{
    return item.Amount.HasValue; 
}

现在,问题是数据提供者不会进入该方法并尝试弄清楚如何将其转换为 SQL。

数据提供者非常有能力遍历表达式树来构建 SQL,这就是“减号”示例的工作原理,也是您帖子中链接的相关答案。

如果您可以用您想要完成的内容更新您的帖子,我也许可以帮助您。

【讨论】:

  • 很好的解释,谢谢。你可能已经回答了我的问题:这是不可能的。基本上我正在尝试做你说我不能做的事情:将我的表达式存储在一个变量中,以供重用,并将其传递给Count()
  • 其实一个表达式。它是一个表示创建委托的表达式,因此所有信息在表达式中,理论上它可以翻译成SQL。查询提供者根本不期望这个特定的操作,所以它会出错,但那是因为他们没有预料到它并围绕它编写代码,而不是因为他们需要的信息不存在。
  • @Servy 我明白你的意思,但是无论我将表达式拉出到变量中还是简单地将表达式内联,我都会得到同样的异常。你确定迈克的建议不正确吗?理论上,你说的有道理(我也是这么想的)。但在实践中,.NET 似乎以某种方式将强制转换与未强制转换的表达式区别对待。
  • 您要存储的表达式是否有任何模式?例如,所有表达式都将评估某些属性(在运行时确定)是否可以为空?
猜你喜欢
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-22
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多