EF Core 可选列按需要处理

EF Core Optional Column Treated As Required

我需要从 EF Core 调用的存储过程中读取结果,其中包括用于电子表格格式化目的的内容,例如仅包含空值的行。我的代码大部分工作正常,但有两列在我包含它们时导致查询失败。

这是我的模型 class(为简洁起见,仅包含一些道具):

public class StoredProcRecord
{
    [Column("Prod Line")]
    public string ProductLine { get; set; }

    [Column("Current Sales")]
    public decimal? CurrentSales { get; set; }

    [Column("Current Margin $")]
    public decimal? CurrentMargin { get; set; }
}

如果我 运行 来自 SQL Server Management Studio 的存储过程,这里是部分输出的片段:

以下是我在数据库上下文中使用 EF Core 将类型注册为实体模型的方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Query<StoredProcRecord>();
}

下面是我调用存储过程的方式:

return _context.Query<StoredProcRecord>().FromSql("EXECUTE my_stored_proc").ToList();

在此示例中,EF Core 在尝试调用 FromSql() 时总是抛出异常并显示一条消息:

The required column 'Current Margin $' was not present in the results of a 'FromSql' operation.

根据 EF Core docs,只要列可以为 null,则不需要。但是,我收到了要求 "Current Margin $" 是必需的例外情况。它也只发生在 CurrentMargin 属性,而不是 CurrentSales 属性,它们使用相同的类型。如果我删除 CurrentMargin,整个事情都很好,我只是缺少那个 属性。

我试过使用 [Column(Order = 2)] 而不是命名列,我想列名中的美元符号可能与它有关,但结果是:

The required column 'CurrentMargin' was not present in the results of a 'FromSql' operation.

同时包含顺序和名称会导致相同类型的错误。

值得注意的是,这不是我可以选择对其进行更新的存储过程。

CurrentMargin 属性 与 CurrentSales 相比有什么不同导致它像这样失败?是否有一些特殊的方法需要处理列名中的美元符号?我是否完全遗漏了其他东西?

编辑:

这是存储过程最后的一个片段,其中输出结果 table。我包含这个是为了表明 "Current Margin $" 确实是列名之一。实际上,我直接从存储过程 copied/pasted 只是为了确保我没有输入错误的列名。

BEGIN
-- bulk of stored procedure that builds #tmp_tbl omitted for length
SELECT 
'Prod Line'          = pl_key,
'Current Sales'      = curr_sales,
'Current Margin $'   = curr_margin
FROM #tmp_tbl
END

这个问题的尴尬答案是确保你仔细阅读你的代码,尤其是像字符串值这样的东西。

在这种情况下,我有两个最终将被我的应用程序使用的存储过程,bv_xls_profit_sum_v2bv_xls_prod_sum_v2。我正在实现对第一个存储过程结果的使用,但我不小心将第二个存储过程的名称提供给了 EF。这两个列不匹配,因此我收到的关于缺少必需列的错误与列是否可为空无关,但实际上是结果集中确实完全缺少该列的情况。通过 SQL Server Management Studio 进行测试时,这并不明显,因为我没有意识到我是 运行 一个不同的存储过程。

奖金"Answer":

在弄清楚我的愚蠢错误之前,我确实想出了一个解决方法,我会把它留在这里,以防它对任何人有用。我的应用程序有自己的 SQL 服务器实例,但也查询不受应用程序控制的另一个 SQL 服务器实例(这是有问题的存储过程所在的位置)。为了解决我一直在努力解决的问题,我将另一个 SQL 服务器实例连接到我的服务器实例作为链接服务器。然后我复制了我想调用的存储过程,更新它以使其查询链接服务器,消除不需要的空行,并 return 使用列名来匹配我的模型 class。这确实有效并允许我管理存储过程,尽管它可能会增加额外的延迟以从查询修改后的存储过程中获取结果集。