【问题标题】:EF Core Optional Column Treated As RequiredEF Core 可选列按要求处理
【发布时间】:2019-08-07 02:10:27
【问题描述】:

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

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

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 运行存储过程,这是部分输出的 sn-p:

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

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

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

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

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

结果中不存在所需的列“当前保证金 $” 'FromSql' 操作。

根据EF Core docs,只要列可以为空,则不需要。然而,我收到声称需要“当前保证金 $”的例外情况。它也只发生在CurrentMargin 属性上,而不是CurrentSales 属性,它使用相同的类型。如果我删除 CurrentMargin,整个事情都会正常工作,而我只是缺少那个属性。

我尝试使用[Column(Order = 2)] 代替命名列,认为列名中的美元符号可能与它有关,但这会导致:

所需的列“CurrentMargin”未出现在结果中 'FromSql' 操作。

同时包含 order 和 name 会导致相同类型的错误。

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

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

编辑:

这是存储过程最后的一个 sn-p,输出结果表。我将其包括在内是为了表明“当前保证金 $”确实是列名之一。我实际上是直接从存储过程中复制/粘贴的,只是为了确保我没有输入错误的列名。

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

【问题讨论】:

  • Yet, I receive that exception that claims "Current Margin $" is required. -不,这不是!它实际上是在查询返回的输出中没有名为Current Margin $ 的列。
  • 看起来 SP 返回的列名不是 'Current Margin $'。检查 $ 后的空格或其他符号。
  • 问题是,我已经尝试过帖子中的代码,它可以像这样CREATE PROCEDURE [dbo].[my_stored_proc] AS DECLARE @DATA TABLE(ProductLine VARCHAR(20), CurrentSales decimal, CurrentMargin decimal); insert into @DATA values('1', 1, 1); insert into @DATA values('2', 2, 2); insert into @DATA values('3', 3, 3); insert into @DATA values('4', 4, 4); insert into @DATA values(null, null, null); select T.ProductLine [Prod Line], T.CurrentSales [Current Sales], T.CurrentMargin [Current Margin $] from @DATA T; RETURN 0 与测试 SP 一起使用,换句话说,它不会重现
  • @IvanStoev 嗯...您的样本确实如我所料。不幸的是,这只会让原始问题更加令人费解,因为来自原始 SP 的错误专门将“当前保证金 $”作为问题字段,但无论如何我都无法让您的 SP 以任何类似的方式失败尝试修改它。
  • 你知道吗,你的 SP 的 SELECT 看起来很奇怪,可能返回的所有列名都不是你所期望的 - EF Core 只报告 alphabetical 中第一个丢失的列名i> 订购。要查看你得到了什么,请执行以下 sn -p var cn = _context.Database.GetDbConnection(); var cmd = cn.CreateCommand(); cmd.CommandText = "my_stored_proc"; cn.Open(); var dr = cmd.ExecuteReader(); var cols = Enumerable.Range(0, dr.FieldCount).Select(i =&gt; dr.GetName(i)).ToList(); 并检查调试器中的 cols 变量。

标签: c# sql-server entity-framework ef-core-2.0


【解决方案1】:

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

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

奖励“答案”:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-01
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多