Entity Framework 核心中的存储过程 "enumeration yielded no results" 错误

Stored procedure in Entity Framework Core "enumeration yielded no results" error

在我使用 EF Core 1.1 的 ASP.NET Core 1.1 项目中,我试图通过遵循此 official MSDN article and 来调用 SQL 服务器存储过程。但是我在以下代码的 While loop 中遇到了上述错误。

我已经使用 SQL Server Profiler 验证存储过程在

处被成功调用
DbDataReader oReader = await cmd.ExecuteReaderAsync();

行,当我 运行 在 SSMS 中捕获的 SQL 调用时,它会 return 正确的记录数。

那么为什么我会收到错误消息以及如何解决它?由于此错误,应用无法 return 视图中的结果。

注意:您可能已经注意到我正在使用 ADO.NET 和 EF 提供的数据库连接 [参考:上述 MSDN 文章]

public async Task<List<CustOrderViewModel>> getOrderReport(int SelectedYear, byte SelectedOrderType)
{
    List<CustOrderViewModel> lstOrderReport = new List<CustOrderViewModel>();

    using (SqlConnection conn = (SqlConnection)_context.Database.GetDbConnection())
    {
        await conn.OpenAsync();

        using (SqlCommand cmd = conn.CreateCommand())
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "getOrderReport_SP";
            cmd.Parameters.AddWithValue("@year", SelectedYear);
            cmd.Parameters.AddWithValue("@orDerType", SelectedProjType);

            DbDataReader oReader = await cmd.ExecuteReaderAsync();

            if (oReader.HasRows)
            {
                while (await oReader.ReadAsync())
                {
                    var row = new CustOrderViewModel
                    {
                        SelectedOrderYr = oReader.GetInt32(0),
                        OrderNumber = oReader.GetString(1),
                        OrderDesctiption = oReader.GetString(3),
                        OrderType = oReader.GetByte(8)
                    };
                    lstOrderReport.Add(row);
                }
            }

            oReader.Dispose();
        }
    }

    return lstOrderReport;
}

ORM 和微型 ORM 的好处之一是它们通常会为您处理可为 null 的数据。

但是,在低级别工作时(直接使用ADO.NET),您需要自己处理所有事情。 DbDataReader 意味着你应该在调用具体的 GetXXX 方法之前使用 IsDBNull 方法。

因此,如果 OrderDesctiption 列可以为 null,为避免异常,您应该使用类似这样的东西

OrderDesctiption = !oReader.IsDBNull(3) ? oReader.GetString(3) : null,

类似于任何其他可为空类型的列。

因为在很多地方这样做很烦人,我宁愿创建一个像这样的小辅助扩展方法实用程序:

public static class DataReaderExtenstions
{
    public static string GetNString(this DbDataReader reader, int ordinal)
    {
        return !reader.IsDBNull(ordinal) ? reader.GetString(ordinal) : null;
    }
    public static int? GetNInt32(this DbDataReader reader, int ordinal)
    {
        return !reader.IsDBNull(ordinal) ? reader.GetInt32(ordinal) : (int?)null;
    }
    // Similar for Int16, Byte, Decimal, Double, DateTime etc.
}

并在需要时使用 N(可为空)版本:

OrderDesctiption = oReader.GetNString(3),