LINQ的“无法表达......转化为SQL,不能把它当作一个局部表达。”(Linq “Could

2019-06-18 08:45发布

我开始了这个问题 ,我有点回答有 ,现在我在这里问的更根本的问题。 我已经简化了查询到这一点:

var q = from ent in LinqUtils.GetTable<Entity>()
        from tel in ent.Telephones.DefaultIfEmpty()
        select new {
          Name = ent.FormattedName,
          Tel = tel != null ? tel.FormattedNumber : "" // this is what causes the error
        };

tel.FormattedNumber是结合了一个属性NumberExtension领域成整齐的格式化字符串。 下面是导致错误:

System.InvalidOperationException: Could not translate expression 'Table(Entity).SelectMany(ent => ent.Telephones.DefaultIfEmpty(), (ent, tel) => new <>f__AnonymousType0`2(Name = ent.FormattedName, Tel = IIF((tel != null), tel.FormattedNumber, "")))' into SQL and could not treat it as a local expression.

如果我从改变高于参考FormattedNumber只是普通的Number ,一切工作正常。

但我想格式化的数字在我的名单上完美呈现。 你有什么建议的最巧妙的,这样做的最彻底的方法?

Answer 1:

你可以使用AsEnumerable的实体,但是这将迫使它带回所有列(即使不使用); 或许反而是这样的:

var q1 = from ent in LinqUtils.GetTable<Entity>()
         from tel in ent.Telephones.DefaultIfEmpty()
         select new {
           Name = ent.FormattedName,
           Number = (tel == null ? null : ent.Number),
           Extension = (tel == null ? null : ent.Extension)
         };

var q2 = from row in q1.AsEnumerable()
         select new {
             row.Name,
             FormattedNumber = FormatNumber(row.Number, row.Extension)
         };

其中FormatNumber是一些方法,它采用了两个合并它们,想必从其他(财产)的代码重新使用。

随着LINQ到SQL,另一种选择是揭露一个UDF上,做数据库内的数据格式化上下文; 一个稍微不同的实施例:

var qry = from cust in ctx.Customers // and tel
          select new {
              cust.Name,
              FormattedNumber = ctx.FormatNumber(tel.Number, tel.Extension)
          };

(这将做的工作,在数据库中;而不论这是否是一个好主意;-p)



Answer 2:

清洁的方法是说明你其实想表达的领域,把它们放在中间层的对象,然后使用任何辅助功能对其进行修改后者。

我不知道你是否意识到,对LINQ一类代表SQL表是一个DTO类 - 它定义了LINQ-SQL翻译使用的语法。 注入一个属性,不映射到SQL表中的DTO甚至不支持 - 这意味着翻译可以开火的意志。 属性定义的语法和任何不被他们定义为表达翻译不存在。

在FROM子句中命名实体不是对象 - 它们是用来帮助阐明,这将是获取实际的表中的字段只是符号。 没有选择明确指定一个字段是不是牵强 - 至少这是译者的目标,它可能通过让滑数。 例如,如果是ent.FormattedName没有声明,这是一个滑可能会发生爆炸后者。

因此,注入到DTO类FormattedNumber财产甚至没有在语法中存在。 这不是一个“计算的领域” - 这个词是严格的SQL表定义,如果你有一个它会在DTO的语法。 请注意,错误说非常精确地“地方表达” - 范围非常有限。

您可以尝试通过嵌套lambda表达式在整个“电话”,它可能通过靶向整个记录的获取调用静态函数欺骗 - 或者抛出另外的异常。

其他LINQ-S,这是不是翻译,可以有放宽的规定。 LINQ-SQL,必须为很严格,非常缓慢的,它已经够慢:-)



Answer 3:

@Marc Gravell打我的答案,信贷也以各种应答者对这个问题谁把我在正确的轨道上。

我做到了,就像马克的第一个建议,像这样:

var q1 = from ent in LinqUtils.GetTable<Entity>()
         from tel in ent.Telephones.DefaultIfEmpty()
         select new { ent, tel };
var q2 = from q in q1.AsEnumerable()
         select new {
           Name = q.ent.FormattedName,
           Tel = q.tel != null ? q.tel.FormattedNumber : ""
         };

而且做到了! 谢谢大家!



文章来源: Linq “Could not translate expression… into SQL and could not treat it as a local expression.”