简体   繁体   中英

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.

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. 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. This is a inline sql statement so the sql statement is not changing and the table schema of the database is the same. Its doing this on int primary keys Anyone have any ideas?

I originally thought the was a 2000 to 2008 issue but I now have the some problem on 2008 as well. Both databases are on the same instance of sql server these are the connection strings

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

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.

C# Code (Note reader is type 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.

I don't think the C# code comes from this, its a 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"

2008 Table A Def

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

2008 Table 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

     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. 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.

I believe the OTHER table, the one that you JOIN to, has a different data type in one database.

What is the datatype of File_fileType.Id in both DBs?

Your 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.

Can you show the DDL for both versions of both tables in the above JOIN ?

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.

They have a 14-day trial. I would try downloading it and running a comparison between your databases.

do the SQL collation's match? 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.

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

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. 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.

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. 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). 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 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. (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.

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.

Seeing as you haven't resolved this perhaps try the GetSqlInt32 method instead.

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

Note I've not included the IsDBNull check since, combining SqlInt32 with ToNullableInt32 copes with this.

Where ToNullableInt32 is an extension method.

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()

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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