C# 使用SqlBulkCopy插入guid

C# 使用SqlBulkCopy插入guid,c#,sql-server,sql-server-2008,sqlbulkcopy,C#,Sql Server,Sql Server 2008,Sqlbulkcopy,我正在尝试使用SQL Server管理导入导出向导创建的flatfiles中的SqlBulkCopy类进行大容量插入。这些文件以逗号分隔 文件中的一行可以如下所示: [DCAD82A9-32EC-4351-BEDC-2F8291B40AB3},{ca91e768-072d-4e30-aaf1-bfe32c24008f},900001:1792756900001:1792757,basladdning,2011-04-29 02:54:15380000000,basladdning,2011-04

我正在尝试使用SQL Server管理导入导出向导创建的flatfiles中的
SqlBulkCopy
类进行大容量插入。这些文件以逗号分隔

文件中的一行可以如下所示:

[DCAD82A9-32EC-4351-BEDC-2F8291B40AB3},{ca91e768-072d-4e30-aaf1-bfe32c24008f},900001:1792756900001:1792757,basladdning,2011-04-29 02:54:15380000000,basladdning,2011-04-29 02:54:15380000000,{20A3C50E-8029-41DE-86F1-DDCD9AB785}

我得到的错误是:

System.InvalidOperationException未处理
消息=无法将数据源中类型字符串的给定值转换为类型 指定目标列的唯一标识符

所以问题是从字符串到GUID的转换

我尝试了以下方法:

  • 尝试了不同的编码,UTF8和ANSI
  • 删除了guid周围的{}
  • 在GUID周围添加了“”,包括和不包括{}
有什么建议吗?在“”所在的平面文件中,是一列,该列的Guid也是数据类型。向导将该列导出为“”时,该列为空。这就是问题所在吗

守则:

using (var file = new StreamReader(filePath))
using (var csv = new CsvReader(file, false)) 
using (var bcp = new SqlBulkCopy(CreateConnectionString()))
{
    bcp.DestinationTableName = "table";
    bcp.WriteToServer(csv);
}
表定义:

CREATE TABLE [beata].[T_FeatureInstance]( 
    [FeatureInstanceId] [uniqueidentifier] NOT NULL, 
    [FeatureInstanceParentId] [uniqueidentifier] NULL, 
    [FeatureTypeAliasId] [uniqueidentifier] NOT NULL, 
    [Uuid] [varchar](1000) NOT NULL, 
    [VersionId] [varchar](50) NOT NULL, 
    [SkapadAv] [varchar](255) NULL, 
    [Skapad] [datetime] NOT NULL, 
    [UppdateradAv] [varchar](255) NOT NULL, 
    [Uppdaterad] [datetime] NOT NULL, 
    [Gs] [uniqueidentifier] NOT NULL,

在uniqueidentifier列中插入的标准内容如下所示(已测试且有效),因此回答了格式化问题。该列是否允许空值

插入到dbo.TableName([GUID])
值('20A3C50E-8029-41DE-86F1-DDCDB9A78BA5')

问题在于,{code>{DCAD82A9-32EC-4351-BEDC-2F8291B40AB3},{ca91e768-072d-4e30-aaf1-bfe32c24008f}中的空列被解释为
'
,而不是
NULL
。我刚刚在本地数据库上尝试了一个
INSERT语句
,当我指定
NULL
而不是
'
您可能会遇到另一个错误:

Conversion failed when converting date and/or time from character string.
原因是SQL只允许毫秒的3位十进制精度。因此,您必须将
'2011-04-29 02:54:15.380000000'
四舍五入到
'2011-04-29 02:54:15.380'
,它将正常工作

这样做的一种方法是如上所述
或者,在CsvReader.GetValue(int)函数中,当值为string.Empty时,可以修改CsvReader代码以返回DBNULL。看看

我想我找到了一个答案,适合那些正在使用一个叫做BulkDataReader的流行免费代码类的人。我也有同样的问题,我试着在前一段时间发布这个问题,但自从我问了另一个问题后,我就开始发帖了 问题,但没有提供答案,该职位已被删除。没关系,我不知道那是违反规定的

这一次,我得到了一个答案,所以希望这篇文章能留在这里。 我将离开问题的设置部分,这样就可以很好地定义问题,没有人会对为什么解决方案对他们不起作用感到困惑。我从中获得了BulkDataReader类的代码 一位同事,他似乎从另一个著名的答案来源得到了这个答案,这样每个人都会知道如何从搜索引擎中找到BuddataReader

此问题的设置如下所示:

我也尝试了CSV文件中GUI的各种格式,包括: N'3192E434-F479-4B32-B516-AC658F4B7B89' {3192E434-F479-4B32-B516-AC658F4B7B89} (3192E434-F479-4B32-B516-AC658F4B7B89) “{3192E434-F479-4B32-B516-AC658F4B7B89}”

我的CSV中的真实样本行是: 1,AAPL,452.20122013-01-24 13:24:27.0003192E434-F479-4B32-B516-AC658F4B7B893192E434-F479-4B32-B516-AC658F4B7B89

如果我删除2个guid并导入到一个没有这些列的表中,它就可以正常工作。使用指向唯一标识符列的GUID,我会出现以下错误: Message={“无法将数据源中类型字符串的给定值转换为指定目标列的类型唯一标识符。”}

我的控制代码非常基本,BulkDataReader非常麻烦,所以如果您试图调试它,请做好准备

using (IDataReader reader = new BulkDataReader(new StreamReader("C:\\test.csv"), false))
        {
            String connectionStr = GetConnString();
            SqlConnection connection = new SqlConnection(connectionStr);
            connection.Open();

            SqlTransaction transaction = connection.BeginTransaction();
            try
            {
                SqlBulkCopy copy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction);
                copy.DestinationTableName = "TestTable6";
                copy.WriteToServer(reader); //ERROR OCCURS HERE: The given value of type String from the data source cannot be converted to type uniqueidentifier of the specified target column
                transaction.Commit();
            }
            catch (Exception exe)
            {
                transaction.Rollback();
            }
            finally
            {
                connection.Close();
            }
        }
因此,错误实际上发生在.NET SqlBulkCopy类中。但是,它发生在BulkDataReader读取Guid值之后。该GetValue方法是从外部调用的 代码意味着它隐藏在BulkDataReader的streamReader和SqlBulkCopy类中的StreamWriting内容之间的管道中。没有必要深入研究所有这些问题 我最喜欢的反射工具。我发现,当BulkDataReader的方法IDataRecord.GetValue(int I)返回一个实际上是Guid的字符串时,SqlBulkCopy无法转换该字符串 到一个唯一的标识符,不管它是什么格式。可能有一些模糊和编码格式,但我找不到一个将工作。但是,如果我只是将值返回为 正确的System.Guid类型,然后SqlBulkCopy将其转换为唯一标识符。因此,一个简单的解决方案似乎是一个噩梦般的序列化问题。只需把它抄过来就行了 整个IDataRecord.GetValue(inti)方法都使用了这个函数,它应该可以工作。我尝试了许多CLR-to-SQL数据类型,但不是所有的,因此可能还有另一种需要使用的数据类型 玩这个反序列化游戏,但这应该在很大程度上解决问题

  object IDataRecord.GetValue(int i)
    {
        ValidateDataReader(DataReaderValidations.IsInitialized | DataReaderValidations.IsNotClosed);

        if (((IDataRecord)this).IsDBNull(i))
            return DBNull.Value;
        else
        {
            //For some reason the SqlBulkCopy.WriteToServer method will call this GetValue method when reading 
            //the value and it doesn't seem to know how to convert the string value of a Guid to a unique identifier.
            //However, it does actually know how to convert a System.Guid to a UniqueIdentifer so we can return that if
            //the value parses to Guid
            if (IsGuid(this[i]))
                return Guid.Parse(this[i]);
            else
                return this[i];
        }
    }

    bool IsGuid(object value)
    {
        if (value != null)
        {
            Guid testGuid = Guid.Empty;
            if (Guid.TryParse(value.ToString(), out testGuid))
                return true;
        }

        return false;
    }

我希望这对某人有所帮助,很抱歉我第一次违反了博客规则。

在您的
数据表中。列。添加
将数据类型作为第二个参数。这应该能奏效。
例如:


检查列数及其类型是否与csv匹配。看起来正在使用csv中的非Guid数据更新DB Guid列。据我所知,Microsoft声明大括号在GUID字符串中有效。@Artemix几乎肯定是正确的。这将是值得张贴您的目的地表DDL。好吧,我不知道你们想如何张贴,但我希望所需的信息在这里;创建表[beata]。[T_FeatureInstance]([FeatureInstanceId][uniqueidentifier]不为空,[FeatureInstanceParentId][uniqueidentifier]为空,[FeatureTypeAliasId][uniqueidentifier]不为空,[Uuid][varchar](1000)不为空,[VersionId][varchar]
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(Guid));