【问题标题】:Why isn't it possible to combine LINQ to XML with LINQ to SQL?为什么不能将 LINQ to XML 与 LINQ to SQL 结合起来?
【发布时间】:2014-11-25 09:53:28
【问题描述】:

我有这段代码:

var xml = XDocument.Load(filePath);
var taxReturns = (from t in xml.Descendants("aangiftes").Elements()
    where t.Name == "ib"
    select new Domain.TaxReturn
    {
        FiscalNumber = t.Attribute("sofinr").Value,
        Guid = Guid.Parse(t.Attribute("guid").Value),
        LastFormOpen = t.Attribute("lastformview").Value,
        Name = string.Empty, 
        TaxYear = t.GetAttributeValue<short>("belastingjaar"),
        TaxForm =  unitOfWork.TaxForms.FirstOrDefault(tf => tf.Code == t.Attribute("biljetsoort").Value),
    }).ToArray();

当我运行这段代码时,我得到了这个异常:

LINQ to Entities 无法识别 System.Xml.Linq.XAttribute Attribute(System.Xml.Linq.XName)-method 方法,并且该方法无法转换为存储表达式

但是,当我将此行提取到方法中时,它可以正常工作。

有人可以解释这种行为吗?我不明白这种行为:/

【问题讨论】:

  • 当您收到错误时,它正在尝试将 FirstOrDefault 调用中的表达式转换为 SQL。
  • LINQ to SQL 在哪里发挥作用?您是说 LINQ to Entities 吗?
  • @BenRobinson 你能详细说明一下吗?
  • @Rik unitOfWork 是围绕 DbContext 的包装器。 unitOfWork 进入数据库

标签: c# linq linq-to-sql linq-to-xml


【解决方案1】:

这是因为 LINQ 试图将 Domain.TaxReturn {...} 中的代码编译成 SQL。 XElement.Attribute(...) 的 SQL 中没有对应的 API,因此它失败了。

尝试将 XElement 依赖代码移出 Domain.TaxReturn {...}
像这样:

var xml = XDocument.Load(filePath);
var taxReturns = (from t in xml.Descendants("aangiftes").Elements()
    where t.Name == "ib"
    let sofinr = t.Attribute("sofinr").Value
    let guid = Guid.Parse(t.Attribute("guid").Value)
    let lastformview = t.Attribute("lastformview").Value
    let belastingjaar = t.GetAttributeValue<short>("belastingjaar")
    let biljetsoort = t.Attribute("biljetsoort").Value
    select new Domain.TaxReturn
    {
        FiscalNumber = sofinr ,
        Guid = guid,
        LastFormOpen = lastformview,
        Name = string.Empty, 
        TaxYear = belastingjaar,
        TaxForm = unitOfWork.TaxForms.Single(tf => tf.Code == biljetsoort),
    }).ToArray();

(未经测试)

另外,您可能想要使用Enumerable.Single 而不是Enumerable.FirstOrDefault,或者null 是一个有效的案例?

【讨论】:

  • 谢谢! Linq 2 Sql 在 linq 查询中总是优先吗?我的意思是,它也是一个 Linq to Xml 查询。编辑:null 是一个有效值 :)
  • 编译器从上下文中推断出一个 LINQ 表达式是否要转换为 Expression&lt;Func&lt;...&gt;&gt; 或只是一个普通的 Func&lt;...&gt;Expressions&lt;&gt; 在运行时被翻译成其他语言(在这种情况下是 SQL),而 Funcs 被正常编译。
  • 你知道编译器为什么要把这个查询翻译成SQL吗? Qhy not to XML?我的意思是,我现在同时使用 XML 和 SQL,但编译器“选择”使用 SQL。我不明白。
  • 编译器看到Domain 是一个数据库上下文,因此知道括号内的代码必须通过表达式API 转换为SQL。谷歌获取 LINQ 表达式 API 以了解更多信息。
  • 呵呵,我在您编辑您的评论时发表了我的评论 :) 我为 LINQ 表达式 API 进行了一些谷歌搜索,但找不到我认为您所指的内容。你指的是表达式树吗?
【解决方案2】:

如文档中所述 -

当应用程序运行时,LINQ to SQL 将对象模型中的语言集成查询转换为 SQL 并将它们发送到数据库执行

http://msdn.microsoft.com/en-us/library/bb386976%28v=vs.110%29.aspx

仔细查看执行顺序,“先生成SQL再执行”

您可以很容易地理解为什么会发生这种情况。 SQL 中没有System.Xml.Linq.XAttribute Attribute(System.Xml.Linq.XName) 的替代品。

例如,.OrderBy() 有一个 SQL 等效的 order by,因此当 LINQ 看到此方法时,它会将其转换为 order by 并执行查询。但是当 linq 看到 System.Xml.Linq.XAttribute Attribute(System.Xml.Linq.XName) 时,没有与之对应的 SQL 并且 LINQ 会抛出一个错误,说它无法识别它。

但是当您将行提取到一个方法中时,该方法首先执行,因此此时 LINQ to SQL 已经工作,并且您要查找的所有实体都被带到 RAM 中,现在您可以执行任何 LINQ to XML。这次查询没有转换为 SQL,因为实体已经作为托管对象在 RAM 中,并且您的代码可以正常工作。

【讨论】:

  • 谢谢。在我的示例代码中,我只展示了一个需要来自数据库的对象的属性。实际上我有 6 个。我现在应该创建 6 个方法来从数据库中获取对象吗?还是有其他更简洁的方式?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多