【问题标题】:SQL: Specified cast is not validSQL:指定的强制转换无效
【发布时间】:2012-06-12 21:01:17
【问题描述】:

注意:我正在寻找为什么会发生这种情况以及如何解决它,我不是在寻找解决方法。这似乎是服务器(SQL Server 或连接字符串)问题。

我有一个连接到 sql 2008 数据库(数据库 A)的程序,并且我有运行的内联 sql,它返回了整数和字符串,它工作正常。但是我被要求切换到另一个 2008 数据库(数据库 B),现在所有内容都以字符串形式返回,并且我从 C# 得到一个指定的强制转换无效,当我连接到 sql 2008(数据库 A)时不说这个。这是一个内联 sql 语句,因此 sql 语句没有变化,并且数据库的表模式是相同的。它在 int 主键上这样做有人有什么想法吗?

我最初认为这是 2000 年到 2008 年的问题,但我现在在 2008 年也遇到了一些问题。两个数据库都在同一个 sql server 实例上,这些是连接字符串

连接字符串

  Server=Server01\instance;Database=Fraud_Micah; Trusted_Connection=yes <- Server 2008 (this one does not)
  Server=Server02\instance;Database=Fraud; Trusted_Connection=yes <- Server 2008 (this one works)

两个数据库的数据库兼容性级别均为 100

select 语句

select *, delimeter, file_filetype.LocalPath, ArchiveDir, EmailList
from file_importtable 
join file_filetype on file_importtable.FileTypeID = file_filetype.ID
where importsuccessdate is null and transferdate is not null
and remotediscoverdate is not null 
and OriginalFileName in ('Test987.xml.pgp')

fileTypeID 是崩溃的地方 -> InvalidCastException: Specified cast is not valid.

C#代码(注意阅读器是SQLDataReader类型)

if (!(reader.IsDBNull(reader.GetOrdinal("FileTypeID"))))
{
    file.FileTypeID = reader.GetInt32(reader.GetOrdinal("FileTypeID"));
}

这里是列定义:[FileTypeID] [int] NULL,表中没有空值。

我不认为 C# 代码来自这个,它是一个 int? public int? FileTypeID { get; set; }

在调试模式下:reader["FileTypeID"] -> "1" 实际上是一个字符串,但是为什么当我连接到 2008 数据库时它会返回 1 而不是 "1"

2008 年表 A 定义

[ProcessSuccessDate] [datetime] NULL,
[ProcessSuccessUser] [datetime] NULL,
[FileTypeID] [int] NULL,
[HoldDate] [datetime] NULL,

2008 年表 B 定义

ProcessSuccessDate] [datetime] NULL,
[ProcessSuccessUser] [datetime] NULL,
[FileTypeID] [int] NULL,
[HoldDate] [datetime] NULL,

file.FileTypeID = (int)reader["FileTypeID"]; 产生相同的结果。

做一个

     file.FileTypeID (int)reader.GetInt32(reader.GetOrdinal("FileTypeID"));

确实有效,但我不想对已经应该以 int 形式返回的每一列都这样做,也像这样编写 sql

     select Convert(int, FileTypeID) as FileTypeId, delimeter, file_filetype.LocalPath, ArchiveDir, EmailList

也可以解决这个问题,但是我想知道如果我已经在表中将类型设置为 int,为什么我必须这样做。我还不如把所有类型作为字符串放在表中。在这一点上,我不是在寻找解决方法,我想了解为什么它不能正常工作。

【问题讨论】:

  • 错误信息是否告诉您涉及哪些类型?你能发布完整的错误信息吗?
  • 您确定FileTypeID 实际上是int(而不是long 等)?
  • 那么这个错误很可能来自C#代码。 file.FileTypeID 定义为什么类型?
  • 您能否重新验证您的 2000 和 2008 数据库中的架构是否相同?现在对我来说唯一有意义的是该列更改为varchar
  • 如果在 sql 中进行显式强制转换会发生什么?转换(int,FileTypeId)

标签: c# sql


【解决方案1】:

你必须从字符串中转换。

file.FileTypeID = int.Parse((string)reader["FileTypeID"]);

编辑:如果您想要一个适用于 sql server 2008 和 2000 的解决方法

file.FileTypeID = Convert.ToInt32(reader["FileTypeID"]);

【讨论】:

  • 如果它没有回答问题
  • 如果您不想投射,那么我怀疑您将不得不更改您的提供程序中的某些内容,您使用的是 JET 还是标准的 ADO.net 提供程序?
  • 我正在使用 System.Data.SqlClient 我认为这样就可以了
  • 不确定那是什么,您是否使用msdn.microsoft.com/en-us/library/… (SqlConnection) 并传递连接字符串?编辑:好吧,我不知道出了什么问题。
  • 我不确定是什么原因造成的,但我发布了一个解决方法,它同时适用于 2008 年和 2000 年。
【解决方案2】:

既然你还没有解决这个问题,不妨试试GetSqlInt32 方法。

file.FileTypeID = reader.GetSqlInt32((fieldTypeIDOrdinal).ToNullableInt32();

注意我没有包括 IsDBNull 检查,将 SqlInt32ToNullableInt32 结合可以解决这个问题。

ToNullableInt32 是一个扩展方法。

public static int? ToNullableInt32(this SqlInt32 value)
{
    return value.IsNull ? (int?) null : value.Value;
}

作为旁注,您提到这是一个性能优先应用程序,在这种情况下,您可能希望预先计算您的序数值,而不是在您的 reader.Read() 的每个循环中都有这个 reader.GetOrdinal("FileTypeID")

【讨论】:

  • 我几乎可以肯定数据库或连接字符串有问题,但我不确定是什么
  • 是的,我认为这也与数据库设置或连接字符串/数据提供程序有关。
  • 出于兴趣,您是否尝试过创建一个简单的示例项目(例如基本控制台应用程序)连接到一个简单的数据库、一个表、一个列设置,其中列的类型为 int?可能会在 5 分钟内完成类似的操作,并且可能有助于隔离它是您的代码还是数据库...
  • 这样做了,但仍然遇到同样的问题
【解决方案3】:

file.FileTypeID = Convert.ToInt32(reader["FileTypeID"]); 而不是 file.FileTypeID = (int)reader["FileTypeID"];

【讨论】:

  • 这是同一个概念,一种解决方法,我正在寻找一个原因,为什么事情会以这种方式工作,而不是把它扫到地毯下。谢谢!
【解决方案4】:

SQL 排序规则是否匹配?如果您在数据库之间遇到不同的行为,这可能是您的问题。右键单击每个数据库并选择属性,排序规则应指定为 *Latin1_General_CI_AS* 如果它们不同,则绝对要排除。

【讨论】:

  • 我不知道,但是是的,不幸的是,两个排序规则都匹配,它们是 SQL_Latin1_General_CP1_CI_AS
  • 好的,只是检查一下,数据库匹配的数据类型?
  • 您是否尝试将 SQL 服务器分析器附加到您的数据库,看看 SQL 的运行方式是否有任何不同?一个使用 EXEC 而另一个直接处理 SQL?
【解决方案5】:

对我来说,听起来有些古怪的配置设置很难找到。有一个名为 Redgate SQL Compare 的工具在检测数据库模式之间的差异方面做得惊人

他们有 14 天的试用期。我会尝试下载它并在您的数据库之间进行比较。

【讨论】:

    【解决方案6】:

    Visual Studio(根据this 的 Premium 和 Ultimate 版)带有一个数据库比较工具 - 您选择两个数据库,它会显示差异并为您提供一组脚本,将一个移动到另一个状态。从那里开始并尝试找出不同的配置(因为我认为这是一个配置问题)。查看 Visual Studio 中的 Data\Schema Compare 和 Data\Data Compare。

    【讨论】:

      【解决方案7】:

      已确认至少存在一个错误。由于我没有完整的图像,因此很难精确。因此,我建议进行两次检查。

      首先应使用 INFORMATION_SCHEMA.COLUMNS 对两个数据库进行检查(对于所需级别来说已经足够了),以验证架构是否相同。您可以在 http://msdn.microsoft.com/en-us/library/aa933218(v=sql.80).aspx (SQL 2000) 或 http://msdn.microsoft.com/en-us/library/ms188348 (SQL 2008) 阅读更多关于 INFORMATION_SCHEMA.COLUMNS 的信息。来自不同来源的相同信息。

      示例:

      SELECT * FROM INFORMATION_SCHEMA.COLUMNS;
      

      如果架构相同,则代码中可能存在在您提供的部分中不可见的错误。为了证明您的完整代码一切正确,请通过如下更改您的 select 语句进行简单检查:

      select CAST(fileTypeID as int), ..., file_filetype.LocalPath, ArchiveDir, EmailList
      from file_importtable 
      join file_filetype on file_importtable.FileTypeID = file_filetype.ID
      where importsuccessdate is null and transferdate is not null
      and remotediscoverdate is not null 
      and OriginalFileName in ('Test987.xml.pgp')
      

      如果失败,则在调试模式下使用断点和 F11 逐步测试。 (有时回到根源可能会帮助我们看到我们眼前看不见的东西 - 在这种情况下不太可能)。

      通过以上操作,您会找到原因(希望如此)。

      最后一个提示(这可能是您在做任何其他事情之前的第一步):确保您的 sql 服务器已使用最新的服务包进行修补。

      【讨论】:

        【解决方案8】:

        您列出的两个表都将 int 显示为数据类型,但听起来它们是两个不同数据库中同一个表的两个版本。

        我相信您 JOIN 到的 OTHER 表在一个数据库中具有不同的数据类型。

        两个数据库中File_fileType.Id 的数据类型是什么?

        你的JOIN

        join file_filetype on file_importtable.FileTypeID = file_filetype.ID

        正在导致隐式转换。

        上图显示了 SQL Server 如何允许或执行数据类型转换。

        您能否显示上述JOIN 中两个表的两个版本的 DDL?

        【讨论】:

          【解决方案9】:

          在计划中,我决定删除表并使用重新创建它

          [脚本表] -> [创建]

          来自给我问题的同一张表,然后重新插入所有相同的数据。这解决了这个问题。所以我不相信表格的 DML 改变了,数据也没有改变,但这就是解决我的问题的原因。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-05-27
            • 2014-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多