【问题标题】:SQL Server ISNULL and Entity Framework stored proceduresSQL Server ISNULL 和实体框架存储过程
【发布时间】:2016-02-15 00:33:10
【问题描述】:

我有一个 SQL Server 数据库,我的 MVC 应用程序可以通过 Entity Framework 6 访问它。我有一个存储过程,它执行一些总计并将其存储在临时表中,然后通过最终选择语句返回结果(简化版本):

select isnull(TotalDataShared, 0) as TotalDataShared from #main;

在某些情况下 TotalDataShared 可以为空,所以我必须检查它。 proc 结果的自动生成的 EF 实体如下所示(也简化了):

public partial class getUsageTotals_Result
{
    public decimal TotalDataShared { get; set; }
}

我的 repo 方法像这样调用 proc:

    public UsageTotals GetCurrentUsage(int accountId)
    {
        var ret = _context.getUsageTotals(accountId).First();

        return new UsageTotals {
            DataShared = (double)ret.TotalDataShared
        };
    }

当 #main 中的 TotalDataShared 不为空时,一切正常。当它为空时,我的应用程序中出现以下错误:

“getUsageTotals_Result”上的“TotalDataShared”属性不能 设置为“System.Double”值。您必须将此属性设置为 'System.Decimal' 类型的非空值。

在我看来,它忽略了 ISNULL 命令。我已经尝试将最后一个选择包装在一个表变量中,因为我过去在 EF 中从临时表返回数据时遇到过问题,但没有任何好处。

我也尝试过使用 COALESCE(),它给出了相同的结果。我也尝试在 EF 中删除和重新创建对象,但无济于事。如果它为 null (ISNULL(TotalDataShared, 4.441)),我也尝试返回一个非零浮点值,但这也不会改变任何东西。

不确定接下来要尝试什么。有什么想法吗?

更新: 添加存储过程骨架:

create proc getUsageTotals @accountid int
as

if object_id('tempdb..#main') is not null drop table #main;
create table #main (    

    TotalDataShared float,
)

. . .
. . .

select isnull(TotalDataShared, 4.441) as TotalDataShared from #main;

go

proc 的最后两行是 select 和 "go",所以返回值应该是 select 语句,除非我遗漏了什么。

【问题讨论】:

  • 可以显示程序代码吗?
  • 我添加了 sproc 骨架。这是一个简单的过程,使用普通的内部连接来获取总计并将其插入到临时表中。然后,显示最终选择。
  • isnull 返回第一个参数的数据类型。这是float,映射到C# 中的double。为什么将其定义为decimal?程序中有条件逻辑吗?还是从早期版本的 proc 推断出的元数据?
  • 是的,我最初将它与 proc 的第一个版本相匹配。但是现在已经进行了几次迭代,一切都运行良好,我无需更改任何内容,直到出现 NULL 问题。
  • 您的分析不正确,因为isnull 删除了一个空值这一事实对调用代码完全不透明。它不会影响返回的数据类型,EF 无法知道这一点。您可能会发现您现在在所有呼叫中都收到错误消息。将临时表列定义更改为 TotalDataShared decimal(x,y) 或重做元数据发现以期望浮点数/双精度。

标签: c# sql-server entity-framework isnull


【解决方案1】:

试试这个:

  • 在您的实体框架模型中(打开 .edmx 文件),右键单击 图表背景并选择模型浏览器。
  • 打开复杂类型树。
  • 打开您的存储过程,可能称为 getUsageTotals_Result。
  • 右键单击 TotalDataShared 行并选择属性。
  • 将 Nullable 更改为 true。

我希望这是你需要的。

【讨论】:

    【解决方案2】:

    正如评论中所建议的,如果#main 表中没有结果,该过程将返回 0 行。所以_context.getUsageTotals(accountId) 可能会返回零行,您可以通过以下方式轻松解决:

    var ret = _context.getUsageTotals(accountId)
                      .FirstOrDefault(); // FirstOrDefault!
    
    return new UsageTotals {
        DataShared = (double)(ret == null ? 0 : ret.TotalDataShared);
    };
    

    【讨论】:

      猜你喜欢
      • 2016-10-03
      • 1970-01-01
      • 1970-01-01
      • 2013-03-19
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多