【问题标题】:LINQ - 'Could not translate expression' with previously used and proven query conditionLINQ - '无法翻译表达式'与以前使用和证明的查询条件
【发布时间】:2011-11-26 01:42:27
【问题描述】:

我对 LINQ 相当陌生,无法解决一些行为不一致的问题。任何知识渊博的输入将不胜感激。我在 SO 和其他地方看到了类似的问题,但它们似乎没有帮助。

我有一个非常简单的设置 - 一个公司表和一个地址表。每个公司可以有 0 个或多个地址,如果 > 0,则必须指定一个作为主要地址。我正在尝试处理有 0 个地址的情况,使用外部连接并相应地更改 select 语句。

请注意,我目前将输出直接绑定到 GridView,因此我希望将所有处理都保留在查询中。

以下可以工作

IQueryable query =
    from comp in context.Companies
    join addr in context.Addresses on comp.CompanyID equals addr.CompanyID into outer   // outer join companies to addresses table to include companies with no address
    from addr in outer.DefaultIfEmpty()
    where (addr.IsMain == null ? true : addr.IsMain) == true    // if a company has no address ensure it is not ruled out by the IsMain condition - default to true if null
    select new {
        comp.CompanyID,
        comp.Name,
        AddressID = (addr.AddressID == null ? -1 : addr.AddressID), // use -1 to represent a company that has no addresses
        MainAddress = String.Format("{0}, {1}, {2} {3} ({4})", addr.Address1, addr.City, addr.Region, addr.PostalCode, addr.Country)
    };

但这会将 GridView 中的空地址显示为“, , ()

所以我将 MainAddress 字段更新为

MainAddress = (addr.AddressID == null ? "" : String.Format("{0}, {1}, {2} {3} ({4})", addr.Address1, addr.City, addr.Region, addr.PostalCode, addr.Country))

现在我收到了 Could not translate expression 错误和一堆自动生成的错误代码,这对我来说意义不大。

我添加到 MainAddress 的条件与 AddressID 上的工作条件没有什么不同,所以谁能告诉我这里发生了什么?

非常感谢任何帮助。

【问题讨论】:

  • 可能想在问题中添加“spewey 自动生成的代码”。

标签: asp.net linq linq-to-sql


【解决方案1】:

您得到的错误是告诉您 LinqToSql 无法将您的空检查和 string.Format 表达式转换为 SQL。如果您查看您的第一个查询生成的 SQL(使用 LinqPad 或 SQL Profiler),您会看到如下内容:

SELECT [t0].[CompanyID], [t0].[Name], 
    (CASE 
        WHEN [t1].[AddressID] IS NULL THEN @p0
        ELSE [t1].[AddressID]
     END) AS [AddressID], 
    [t1].[Address1] AS [value], 
    [t1].[City] AS [value2], 
    [t1].[Region] AS [value3], 
    [t1].[PostalCode] AS [value4], 
    [t1].[Country] AS [value5]
FROM [Company] AS [t0]
LEFT OUTER JOIN [Address] AS [t1] ON [t0].[CompanyID] = [t1].[CompanyID]
WHERE ([t1].[IsMain] IS NULL) OR ([t1].[IsMain] = 1)

对于您的AddressID 字段,您可以看到它使用CASE-WHEN 来处理AddressID 为空时的条件。当您为MainAddress 添加CASE-WHEN 时,它会尝试对该字段执行相同的操作,但没有与string.Format 等效的SQL 可用于ELSE 子句,因此它会爆炸。

解决此问题的一种简单方法是使用一种方法来格式化字符串。通过调用私有方法,LinqToSql 不会尝试将 string.Format 转换为 SQL,而是返回填充 Address 对象所需的所有字段。然后该方法可以处理格式。

例如:

LINQ:

....
select new {
    comp.CompanyID,
    comp.Name,
    AddressID = (addr.AddressID == null ? -1 : addr.AddressID),
    MainAddress = FormatAddress(addr)
};

方法:

private static string FormatAddress(Address addr)
{
    return (addr == null ? "" : 
            string.Format("{0}, {1}, {2} {3} ({4})", 
                      addr.Address1, addr.City, 
                      addr.Region, addr.PostalCode, addr.Country));
}

【讨论】:

  • 非常感谢您的大力帮助和解释。我没有意识到 LINQ 会尝试将哪些部分传递给数据库。我一直在学习更多关于这些疯狂的东西......
猜你喜欢
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-26
  • 2021-05-28
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
相关资源
最近更新 更多