Linq 查询错误

发布于 2024-10-29 21:26:49 字数 2046 浏览 0 评论 0原文

我有以下 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));

但出现错误:

转换为值类型“Decimal” 失败是因为物化值 为空。结果类型的 通用参数或查询必须 使用可为 null 的类型。

一旦我添加以下内容,就会出现此错误:

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)

I have following 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));

but I get the error:

The cast to value type 'Decimal'
failed because the materialized value
is null. Either the result type's
generic parameter or the query must
use a nullable type.

this error comes as soon as I add this:

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

If I remove this from above query, it works.

The query is translation of following 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦晓ヶ微光ヅ倾城 2024-11-05 21:26:49

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

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

这就是我解释异常“...或者查询必须使用可为空类型”的这一部分的方式。通过使用投影select account.MinimumInstallment,您将获得一个不可为 null 的类型,即 decimal,它是 account.MinimumInstallment 的类型。

但不确定,只是猜测。

编辑

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

因此,让我们帮助编译器将查询的结果类型推断为 decimal?:(

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

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

编辑 2

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

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

I'd try to rewrite the last two lines of your query like so:

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

That's how I interprete this part of the exception "...or the query must use a nullable type". By using the projection select account.MinimumInstallment you have a non-nullable type, namely decimal which is the type of account.MinimumInstallment.

Not sure though, just a guess.

Edit

The problem might actually be the final assignment var sum = .... Since you don't specify the result type explicitely the compiler will here infer the type to decimal because MinimumInstallment is decimal. The query can actually return null when the selected recordset was empty so the cast to decimal is impossible.

So, let's help the compiler to infer the result type of the query to decimal?:

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

(Replace from ... by your original query or maybe by my modified version above.)

Edit 2

OK, the first Edit didn't work (according to comment in another question). Indeed I could reproduce the issue in a similar example. But the following worked in my example:

var sum = (
    ...
    select account)
    .Sum(a => (decimal?)Math.Abs(a.MinimumInstallment))
    .GetDefaultOrValue();
情何以堪。 2024-11-05 21:26:49

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

怎么样:

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

Try using:
Math.Abs((decimal)(minimumInstallment.HasValue ? minimumInstallment : 0));

How about:

 Math.Abs((decimal)(minimumInstallment!= null ? minimumInstallment : 0));  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文