简体   繁体   English

SQL:指定的强制转换无效

[英]SQL: Specified cast is not valid

Note: I am looking for why this is happening and how to fix it, I am not looking for a workaround. 注意:我正在寻找为什么会发生这种情况以及如何解决它,我不是在寻找解决方法。 This appears to be a server(SQL Server or Connection string) issue. 这似乎是服务器(SQL Server或连接字符串)问题。

I have a program that is connected to a sql 2008 database (Database A) and I have inline sql that runs that has ints and strings returned and it works fine. 我有一个程序连接到一个sql 2008数据库(数据库A),我有内联sql运行,其中有int和字符串返回,它工作正常。 But I have been asked to switch to another 2008 database (Database B) and now everything is coming back as a string and I am getting a specified cast is not valid from C# where when I am connected to the sql 2008 (Database A) it does not say this. 但我被要求切换到另一个2008数据库(数据库B),现在一切都以字符串形式返回,我从C#获取指定的强制转换,当我连接到sql 2008(数据库A)时不说这个。 This is a inline sql statement so the sql statement is not changing and the table schema of the database is the same. 这是一个内联sql语句,因此sql语句不会更改,并且数据库的表模式是相同的。 Its doing this on int primary keys Anyone have any ideas? 它在int主键上执行此操作任何人都有任何想法?

I originally thought the was a 2000 to 2008 issue but I now have the some problem on 2008 as well. 我原本以为这是2000年至2008年的问题,但我现在也有一些问题。 Both databases are on the same instance of sql server these are the connection strings 两个数据库都在sql server的同一个实例上,这些是连接字符串

Connection Strings 连接字符串

  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)

Both databases are at DB compatibility_level of 100 两个数据库的DB compatibility_level均为100

The select Statement 选择声明

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 is where its breaking -> InvalidCastException: Specified cast is not valid. fileTypeID是其中断的地方 - > InvalidCastException: Specified cast is not valid.

C# Code (Note reader is type SQLDataReader) C#代码(注释阅读器是类型SQLDataReader)

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

Here is the column definition: [FileTypeID] [int] NULL , there is no null values in the table. 这是列定义: [FileTypeID] [int] NULL ,表中没有空值。

I don't think the C# code comes from this, its a int? 我不认为C#代码来自于它,它是一个int? public int? FileTypeID { get; set; }

In debug mode: reader["FileTypeID"] -> "1" it is in fact a string but why when I connect to a 2008 database would it return a 1 instaed of a "1" 在调试模式下: reader["FileTypeID"] - >“1”它实际上是一个字符串,但为什么当我连接到2008数据库时它会返回1个“1”的实例

2008 Table A Def 2008表A Def

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

2008 Table B Def 2008年表B Def

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

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

Doing a 做一个

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

does work but I don't want to do that for every column that already should be coming back as a int also writing sql like this 确实有效但我不想为每一个已经应该作为int返回的列也这样做,也写这样的sql

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

can get around the issue as well, however I want to know why I have to do this if I already set the type as a int in the table. 我也可以解决这个问题,但是如果我已经在表格中将类型设置为int,我想知道为什么我必须这样做。 I might as well put all the types as strings in the table. 我不妨把所有类型作为字符串放在表中。 At this point I am not looking for a workaround I want to understand why its not working like it should be. 在这一点上,我不是在寻找一种解决方法,我想要理解为什么它不应该像它一样工作。

Both tables you list show int as the data type, but it sounds like those are two versions of the same table in two different databases. 您列出的两个表都显示int作为数据类型,但听起来这些是两个不同数据库中同一个表的两个版本。

I believe the OTHER table, the one that you JOIN to, has a different data type in one database. 我相信OTHER表,你JOIN表,在一个数据库中有不同的数据类型。

What is the datatype of File_fileType.Id in both DBs? 两个DB中File_fileType.Id的数据类型是什么?

Your JOIN : 你的JOIN

join file_filetype on file_importtable.FileTypeID = file_filetype.ID

Is causing an implicit conversion. 导致隐式转换。

在此输入图像描述

The chart above shows how SQL Server allows or executes data type conversions. 上图显示了SQL Server如何允许或执行数据类型转换。

Can you show the DDL for both versions of both tables in the above JOIN ? 你能在上面的JOIN显示两个版本的两个版本的DDL吗?

To me it sounds like there is some wacky configuration setting that is going to be hard to find. 对我而言,听起来有一些古怪的配置设置很难找到。 There is a tool out there called Redgate SQL Compare that does an amazing job at detecting differences between database schemas. 有一个名为Redgate SQL Compare的工具在检测数据库模式之间的差异方面做得非常出色。

They have a 14-day trial. 他们进行了为期14天的试验。 I would try downloading it and running a comparison between your databases. 我会尝试下载它并在您的数据库之间进行比较。

do the SQL collation's match? SQL排序规则是否匹配? If your experiencing different behaviour between databases this could be your issue. 如果您在数据库之间遇到不同的行为,这可能是您的问题。 Right click on each database and select properties, the collation should be specified as something like *Latin1_General_CI_AS* If they're different it's definitely something to rule out. 右键单击每个数据库并选择属性,排序规则应指定为* Latin1_General_CI_AS *如果它们不同则肯定要排除。

You will have to cast from string. 你必须从字符串中强制转换。

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

EDIT: if you want a workaround that should work for BOTH sql server 2008 and 2000 编辑:如果你想要一个适用于BOTH sql server 2008和2000的解决方法

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

Visual studio (edition Premium and Ultimate according to this ) comes with a database compare tool - you select two databases, it shows you the diff and gives you a set of scripts that move one to the state of other. Visual Studio(根据版本为Premium和Ultimate)附带了一个数据库比较工具 - 您选择两个数据库,它会显示差异并为您提供一组脚本,将一个脚本移动到另一个状态。 Start there and try and sniff out the configuration that differs (as I would expect this to a be a configuration issue). 从那里开始,尝试嗅出不同的配置(因为我希望这是一个配置问题)。 Check out Data\\Schema Compare and Data\\Data Compare in Visual Studio. 在Visual Studio中查看Data \\ Schema Compare和Data \\ Data Compare。

The existence of at least one bug is already acknowledged. 已经确认存在至少一个错误。 Since I don't have the whole image it's difficult to be precise. 由于我没有整个图像,因此很难准确。 Therefore I suggest two checks. 因此,我建议两次检查。

The first check should be on both databases using INFORMATION_SCHEMA.COLUMNS (it's more than enough for the required level) to verify that schemas are identical. 第一次检查应该在两个数据库上使用INFORMATION_SCHEMA.COLUMNS(对于所需级别来说已经绰绰有余)来验证模式是否相同。 You may read more about INFORMATION_SCHEMA.COLUMNS at http://msdn.microsoft.com/en-us/library/aa933218(v=sql.80).aspx (SQL 2000) or http://msdn.microsoft.com/en-us/library/ms188348 (SQL 2008). 您可以在http://msdn.microsoft.com/en-us/library/aa933218(v=sql.80).aspx(SQL 2000)或http://msdn.microsoft.com/上阅读有关INFORMATION_SCHEMA.COLUMNS的更多信息。 en-us / library / ms188348 (SQL 2008)。 The same information from different sources. 来自不同来源的相同信息。

Sample: 样品:

SELECT * FROM INFORMATION_SCHEMA.COLUMNS;

If schemas are identical then there may be a bug in the code that is not visible in the parts you have presented. 如果模式相同,则代码中可能存在一个错误,该错误在您呈现的部分中不可见。 To vefity that everything is correct with you full code make a simple check by changing your select statement as follows: 为了确保一切都正确,您可以通过更改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')

If it fails, then run in debug mode a step by step test using a breakpoint and F11. 如果失败,则在调试模式下使用断点和F11逐步测试。 (Sometimes going back to the roots may help us to see what is invisible infront of our eyes - more unlikely in this case). (有时回到根源可能会帮助我们看到我们眼前看不见的东西 - 在这种情况下更不可能)。

By following the above you will find the cause (hopefully). 通过以上操作,您将找到原因(希望如此)。

One last tip (which may be your first step before doing anything else): be sure that your sql servers are patched with the latest service packs. 最后一个提示(这可能是你做其他事情之前的第一步):确保你的sql服务器使用最新的服务包进行修补。

In the scheme of things I desided to delete the table and recreate it using 在我希望删除表并使用它重新创建它的方案中

[script table as] -> [create] [脚本表为] - > [创建]

from the same table that was giving me issues, then a reinserted all the same data. 从给我问题的同一个表中,然后重新插入所有相同的数据。 This resolved the issue. 这解决了这个问题。 So I don't believe the DML of the Table changed and the data did not change either but this is what resolved my issue. 所以我不相信表的DML发生了变化,数据也没有改变,但这就解决了我的问题。

Seeing as you haven't resolved this perhaps try the GetSqlInt32 method instead. 看来你没有解决这个问题,也许会尝试使用GetSqlInt32方法。

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

Note I've not included the IsDBNull check since, combining SqlInt32 with ToNullableInt32 copes with this. 请注意 ,我不包括IsDBNull从检查,结合SqlInt32ToNullableInt32与此对应。

Where ToNullableInt32 is an extension method. 其中ToNullableInt32是一种扩展方法。

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

As a side note you mentioned this is a performance priority app, in which case you might want to precompute your ordinal values rather than having this reader.GetOrdinal("FileTypeID") every loop of your reader.Read() 作为旁注,您提到这是一个性能优先级应用程序,在这种情况下,您可能需要预先计算您的序数值,而不是使用此reader.GetOrdinal("FileTypeID") reader.Read()每个循环reader.Read()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM