【问题标题】:error in Linq queryLinq 查询中的错误
【发布时间】:2011-04-04 19:16:39
【问题描述】:

我有以下 Linq:

var ownerRegistryId = 731752693037116688;
var excludeTypes = new[]
{
    "CA00", "CA01", "CA03", "CA04", "CA02",
    "PA00", "PA01", "PA02", "PA03", "PA04"
};

var maxStateChangeMonth = 4;
var excludeStatusId = 999;
var includeMortgage = new[] { "CL10", "CL11", "PL10", "PL11" };

 var sum = (
    from account in context.Accounts
    from owner in account.AccountOwners
    where owner.AccountOwnerRegistryId == ownerRegistryId
    where !excludeTypes.Contains(account.AccountType)
    where account.StateChangeDate == null ||
        (account.StateChangeDate.Month - DateTime.Now.Month)
            <= maxStateChangeMonth
    where includeMortgage.Contains(account.AccountType) ||
            account.AccountType.Contains("Mortgage")
    where account.AccountStatusId != excludeStatusId
    select account.MinimumInstallment)
    .Sum(minimumInstallment => Math.Abs(minimumInstallment));

但我得到了错误:

转换为值类型“十进制” 失败,因为物化值 一片空白。结果类型的 泛型参数或查询必须 使用可为空的类型。

我一添加这个错误就会出现:

where (includeMortgage.Contains(account.AccountType) ||
    account.AccountType.Contains("Mortgage"))

如果我从上面的查询中删除它,它会起作用。

查询是以下 SQL 的翻译:

    SELECT Sum(ABS([Minimum Installment])) AS SumOfMonthlyPayments FROM tblAccount 
    INNER JOIN tblAccountOwner ON tblAccount.[Creditor Registry ID] = tblAccountOwner.
    [Creditor Registry ID] AND tblAccount.[Account No] = tblAccountOwner.[Account No] 
    WHERE (tblAccountOwner.[Account Owner Registry ID] = 731752693037116688)
     AND (tblAccount.[Account Type] NOT IN 
    ('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
    AND (DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <= 
   4 OR tblAccount.[State Change Date] IS NULL AND ((tblAccount.[Account Type] IN ('CL10','CL11','PL10','PL11')) OR
    tblAccount.[Account Type] LIKE 'Mortgage')) AND (tblAccount.[Account Status ID] <> 999)

【问题讨论】:

  • @Guffa:错误是:转换为值类型“十进制”失败,因为具体化值为空。结果类型的泛型参数或查询必须使用可为空的类型。
  • 这是编译错误还是运行时错误。
  • @DotnetSparrow:我清理了你的 LINQ 语句。将一堆 &amp;&amp; 运算符更改为 where 运算符。现在更具可读性。
  • account.MinimumInstallment 到底是什么类型?
  • 您是否尝试过更改为decimal? 并使用Math.Abs(minimumInstallment.HasValue ? minimumInstallment : 0)

标签: c# .net linq linq-to-sql


【解决方案1】:

我会尝试像这样重写查询的最后两行:

var sum = (
...
select account)
.Sum(a => Math.Abs(a.MinimumInstallment));

这就是我对异常"...or the query must use a nullable type" 的这一部分的解释。通过使用投影select account.MinimumInstallment,您有一个不可为空的类型,即decimal,它是account.MinimumInstallment 的类型。

不确定,只是猜测。

编辑

问题实际上可能是最终分配var sum = ...。由于您没有明确指定结果类型,因此编译器将在此处将类型推断为decimal,因为MinimumInstallment 是十进制的。当所选记录集为空时,查询实际上可以返回 null,因此无法转换为十进制。

那么,让我们帮助编译器将查询的结果类型推断为decimal?

var sum = (decimal?)(from ... ) ?? 0;

(将 from ... 替换为您的原始查询或我上面的修改版本。)

编辑 2

好的,第一次编辑不起作用(根据另一个问题的评论)。事实上,我可以在类似的例子中重现这个问题。但以下在我的示例中有效:

var sum = (
    ...
    select account)
    .Sum(a => (decimal?)Math.Abs(a.MinimumInstallment))
    .GetDefaultOrValue();

【讨论】:

  • @DotnetSparrow:我有一个新的“编辑 2”。我可以在一个更简单的例子中重现这个问题。 Edit 2 对我有用,试试吧。
【解决方案2】:

尝试使用:
Math.Abs​​((十进制)(minimumInstallment.HasValue ? minimumInstallment : 0));

怎么样:

 Math.Abs((decimal)(minimumInstallment!= null ? minimumInstallment : 0));  

【讨论】:

  • 我试过了,得到:转换为值类型“十进制”失败,因为物化值为空。结果类型的泛型参数或查询必须使用可为空的类型。
  • 这个怎么样? Math.Abs((decimal)(minimumInstallment != null ? minimumInstallment : 0));
  • 同样的事情,但我可能会使用空合并而不是三元 if。 Math.Abs((decimal)(minimumInstallment ?? 0));。此外,如果您确实使用三元,请始终使用 .HasValue 而不是 !=null
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
  • 2015-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多