2009-08-12 81 views
9

我从this question开始,我回答了there,现在我在这里提出更基本的问题。我已经简化了查询到这一点:Linq“无法将表达式...转换为SQL,无法将其视为本地表达式。”

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,一切正常参考。

但我确实希望格式化的数字能够很好地显示在我的列表中。作为最干净最干净的方式,你推荐什么?

回答

11

你可以在实体上使用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-to-SQL,另一种选择是在数据库上进行格式化的数据上下文中公开UDF;稍有不同的例子:

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

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

1

@Marc Gravell打我的答案,信贷也各种回答者this question谁把我放在正确的轨道上。

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

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 : "" 
     }; 

这做到了! 谢谢,所有!

3

干净的方式是陈述你真正想要表达的字段,把它们放在你的中间层对象中,然后使用任何辅助函数来修改它们。

我不确定您是否意识到表示LINQ的SQL表的类是DTO类 - 它定义了LINQ-SQL转换器使用的语法。将属性注入到未映射到SQL表的DTO中甚至不支持 - 这意味着译者可以随意触发。属性定义了语法,并且表达式翻译器不存在任何未定义的语法。

from子句中指定的实体不是对象 - 它们只是用于帮助拼出将被提取的实际表字段的符号。在select中没有明确命名的字段是一个没有被读取的字段 - 至少这是翻译者的目标,它可能不得不让其中的一部分通过。例如,如果该ent.FormattedName没有声明,那是一个滑动,并可能爆炸后者。

因此,注入到DTO类中的FormattedNumber属性甚至不存在于语法中。这不是一个“计算字段” - 该术语严格用于SQL表定义,如果您有一个,它将用DTO的语法。请注意,错误非常精确地表示“本地表达” - 范围非常有限。

您可以尝试通过在整个“tel”上调用静态函数的嵌套lambda表达式来欺骗它,这可能会触发整个记录的提取 - 或者抛出另一个异常。

其他LINQ-s,不是译者,可以放宽规则。 LINQ-SQL必须非常严格或非常慢,并且已经够慢了:-)

相关问题