【问题标题】:Why does SqlDataReader seem to modify the type of its data?为什么SqlDataReader 似乎修改了它的数据类型?
【发布时间】:2021-08-20 12:03:15
【问题描述】:

这个问题是this DBA related question之后的下一步。

我现在有以下 C# 代码,基于变量SqlCommand sqlCommandSqlDataReader sqlDataReader

我正在运行这段代码:

// What's the max difference of two "Own_Table" tupples for "Field_Name" column?
sqlCommand.CommandText = $"SELECT MAX(val - lag_value) FROM " + 
                         $" (SELECT t.{Field_Name} AS val,LAG(t.{Field_Name}) " +
                         $"    OVER(ORDER BY t.{Field_Name}) as lag_value " +
                         $"  FROM {Own_Table} t) AS tmp " +
                         $"WHERE lag_value IS NOT NULL";
sqlCommand.Parameters.Clear();
sqlDataReader = sqlCommand.ExecuteReader();
long max_value = 0;
while (sqlDataReader.Read())
{
    max_value = sqlDataReader.GetInt32(0); <== sometimes NOK
}

对于一个特定的字段,这似乎出错了:对于字段Id,所提到的源代码行生成一个System.InvalidCastException,并提到Specific cast is not valid.

这是正确的,因为在即时窗口中,我可以看到以下结果:

? sqlDataReader.GetFieldType(0).ToString()
"System.Int64"

然而,对应DataTable的列中的DataType似乎是System.Int32,从下面的即时窗口的摘录中可以看出(dt_mainDataTablei表示相应列的索引):

? dt_main.Columns[i].DataType
{Name = "Int32" FullName = "System.Int32"}

在上一个具有相同DataType 的专栏中,一切正常。

所以现在我的问题是:System.Int32 列上的查询结果怎么可能突然决定将System.Int64 作为数据类型,处理这个问题的最佳方法是什么? (我已经尝试用sqlDataReader.GetInt64() 替换所有sqlDataReader.GetInt32() 但这也失败了)。

DataTable dt_main 的结构是从INFORMATION_SCHEMA.COLUMNS 检索如下:

sqlCommand.CommandText = 
  "SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS " + 
  "WHERE TABLE_NAME = @selectedItem";
sqlCommand.Parameters.Clear();
sqlCommand.Parameters.AddWithValue("selectedItem", cmb_Table_Names.SelectedItem);
// cmb_Table_Names contains all table names.
sqlDataReader = sqlCommand.ExecuteReader();

while (sqlDataReader.Read()) // Get the names of all the columns
{
    string tmp_ColName = sqlDataReader.GetString(0);
    string tmp_ColDataType = sqlDataReader.GetString(1);
    Type T = typeof(string);
    switch (tmp_ColDataType)
    { 
        case "int": case "bigint": case "tinyint": case "smallint":
            T = typeof(int);
            break;
        case "bit":
            T = typeof(bool);
            break;
        case "varchar": case "datetime": case "text":
            T = typeof(string);
            break;
        default: 
            T = typeof(string);
            break;
    }
    dt_main.Columns.Add(tmp_ColName,T);

【问题讨论】:

  • 不匹配的明显原因是如果i等于0,因为您的代码之一sn-ps硬编码列序号,而另一个没有。
  • @mjwills:我已经相应地调整了我的问题。
  • 究竟是什么查询导致了这个问题?请向我们显示该确切表格的CREATE TABLE
  • @Damien_The_Unbeliever:i(如列号 i)和固定数字 0 没有关联:我正在查看每一列(因此计数器 i)和我正在运行“SELECT MAX ...”以查看该列中值的最大差异。
  • @jdweng 实际上没有机会在这里有所作为。编译器选项绝不会改变 ADO.NET 的工作方式。它只是没有。我不确定你从哪里得到这个想法,但这不是真的。 几乎可以肯定 OP 正在查询带有 bigint 列的表。但在他们分享CREATE TABLE 之前,无法确定。

标签: c# sql-server sqldatareader


【解决方案1】:

您分析架构信息的代码已损坏。这里:

    case "int": case "bigint": case "tinyint": case "smallint":
        T = typeof(int);

您假设 SQL Server 类型 intbiginttinyintsmallint 都映射到 C# 类型 int(即 .NET Framework 类型 Int32)。

这是不正确的。例如,bigint 对应于 C# 的 long,即 .NET Frameworks 的 Int64

您可以使用以下 MSDN 条目来查找正确的映射:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多