如何从SqlDataReader的uniqueidentifier类型中获取Guid

7

SQL Server 2008(版本10.50.2550)。

我有一个选择查询,返回类型为uniqueidentifier的单个列。

我想将其放入C#变量中,类型为Guid。

以下所有方法都会导致异常。

reader的类型为SqlDataReader。

using (var reader = command.ExecuteReader())
{

    if (reader.Read())
    {       
        Guid guid = reader.GetGuid(reader.GetOrdinal("integ_schemehistoryId")); //1

        Guid guid = Guid.Parse((string)reader["integ_schemehistoryId"]); //2

        Guid guid = (Guid)reader["integ_schemehistoryId"]; //3

        Guid guid = new Guid((string)reader["integ_schemehistoryId"]); //4

        Guid guid = Guid.Parse(reader["integ_schemehistoryId"].ToString()); //5
    }

}

错误1:

System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting from a character string to uniqueidentifier.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.HasMoreRows()
   at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
   at System.Data.SqlClient.SqlDataReader.Read()
   at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()

2号错误:

System.InvalidCastException: Unable to cast object of type 'System.Guid' to type 'System.String'.
   at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()

第三个错误:

System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting from a character string to uniqueidentifier.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.HasMoreRows()
   at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
   at System.Data.SqlClient.SqlDataReader.Read()
   at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()

第四个错误:

System.InvalidCastException: Unable to cast object of type 'System.Guid' to type 'System.String'.
   at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()

5号错误:

System.Data.SqlClient.SqlException (0x80131904): Conversion failed when converting from a character string to uniqueidentifier.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.HasMoreRows()
   at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
   at System.Data.SqlClient.SqlDataReader.Read()
   at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()

2
GetGuid 应该工作。我建议不要使用任何不必要执行两个字符串转换的方法。请提供调用 GetGuid 时出现的错误详细信息。 - Jon Skeet
2
任何使用Guid.Parse的内容。我也期望你的最后一次尝试是可以的。无论何时在Stack Overflow问题中说“我得到错误”或“它不能编译”,您都应该指定这些错误是什么。就目前而言,第一个和最后一个版本看起来都应该没问题。 - Jon Skeet
2
@cja:你说它们是编译时错误。那些是在执行时发生的异常。请在提供信息时更加准确小心...你浪费了大家的时间追逐虚幻的编译时故障。 - Jon Skeet
1
我现在对错误2和3如何同时发生非常困惑。我猜它们发生在不同的行上... 我并不惊讶将其转换为string失败,但是考虑到转换失败后说它是GUID,不清楚为什么转换为Guid也会失败。 - Jon Skeet
@LynnCrumbling 不行。请看最新编辑。 - cja
显示剩余17条评论
7个回答

8
你的数据或SQL语句出了问题。第一种和第三种方法都应该可以使用——个人认为第一种形式最清晰易懂。
但看看堆栈跟踪:
... at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout) at System.Data.SqlClient.SqlDataReader.Read() at Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID()
请注意,失败的是 Read() 调用,而不是 GetGuid 或索引器。
我猜测你的属性被获取了多次,并且有时候它会起作用——这就是为什么在第二种方法中会出现类型转换异常,但对于一些行来说,由于数据或SQL存在问题,它会失败。由于我们不知道你的数据来自何处,所以除此诊断外,我们无法再帮助你,但这是你接下来应该解决的地方。

左连接获取重复键?可以的。 - Triynko

3

正如其他答案所建议的那样,您应该尝试:

Guid guid = Guid.Parse(reader["integ_schemehistoryId"].ToString())

你可能还需要检查你的存储过程和表格,那里可能出了一些问题。


2

这个错误是由SQL产生的。换句话说,你的SQL命令文本存在问题,而不是你的c#代码。


0

在 Oracle 数据库中:

"ID" RAW(16) DEFAULT SYS_GUID() NOT NULL ENABLE, 

这段代码对我很有效:
using (IDataReader dr = ... )
    {
        while (dr.Read())
        {
            var Id = new Guid();
            if (!(dr["ID"] is DBNull)){
                Id = new Guid((byte[])dr.GetValue(dr.GetOrdinal("ID")));
            }                   
        }
        dr.Close();
    } 

0

你尝试过了吗:

Guid guid = new Guid((string)reader["integ_schemehistoryId"]);

是的,请看问题。(也许你在我编辑问题之前发布了这个问题。) - cja
1
我不认为你使用了 new Guid(...) 构造函数,你的问题中提到了你尝试了静态方法 Guid.ParseSQLDataReader 方法 .GetGuid 和从 Reader 对象直接转换为 (Guid),但这三种情况都没有使用构造函数 new - welegan
抱歉,你是对的。我得到了以下错误信息:System.InvalidCastException: 无法将类型为 'System.Guid' 的对象强制转换为类型 'System.String'。 在 Simego.DataSync.DynamicColumns.DataSourceRowOverride.get_EpochSchemeHistoryID() 处。 - cja

0

尝试使用 Guid.Parse 方法

Guid guid = return Guid.Parse((string)reader["integ_schemehistoryId"]);

请看我在问题中的第二次尝试。 - cja
3
@cja: 好的,你传入了错误的数据类型 - 如果调用时正确传入,可能会起作用,但这并不是最佳的处理方式。 - Jon Skeet
@cja 将读取器的值转换为字符串,因为 Parse 方法需要字符串作为参数。 - Nick
当答案只是“尝试使用Guid.Parse方法”时,我进行了反对投票。 - cja
@cja 我也提供了一个链接,告诉你如何正确使用 Guid.Parse 方法。 - Nick
@LynnCrumbling 我在添加最后一条评论时已经这样做了。 - cja

-1
    object val = reader[0];
    Guid g;
    if ( Guid.TryParse(val, out g) )
    {
        return g;
    } 
    else 
    {
        Trace.WriteLine("Error: " + g == null ? string.Empty : g.ToString());   
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接