首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >SqlBulkCopy -无法将数据源中字符串类型的给定值转换为指定目标列的货币类型

SqlBulkCopy -无法将数据源中字符串类型的给定值转换为指定目标列的货币类型
EN

Stack Overflow用户
提问于 2013-08-09 12:25:09
回答 9查看 148K关注 0票数 66

当我试图从DataTable执行SqlBulkCopy时,我得到了这个异常。

代码语言:javascript
复制
Error Message: The given value of type String from the data source cannot be converted to type money of the specified target column.
Target Site: System.Object ConvertValue(System.Object, System.Data.SqlClient._SqlMetaData, Boolean, Boolean ByRef, Boolean ByRef)

我理解这个错误是什么意思,但是我如何才能获得更多信息,比如发生错误的行/字段?数据表由第三方填充,最多可包含200列和10k行。返回的列取决于发送给第三方的请求。所有数据表列都是字符串类型。我的数据库中的列并不都是varchar,因此,在执行插入之前,我使用以下代码格式化DataTable值(删除了不重要的代码):

代码语言:javascript
复制
//--- create lists to hold the special data type columns
List<DataColumn> IntColumns = new List<DataColumn>();
List<DataColumn> DecimalColumns = new List<DataColumn>();
List<DataColumn> BoolColumns = new List<DataColumn>();
List<DataColumn> DateColumns = new List<DataColumn>();

foreach (DataColumn Column in dtData.Columns)
{
    //--- find the field map that tells the system where to put this piece of data from the 3rd party
    FieldMap ColumnMap = AllFieldMaps.Find(a => a.SourceFieldID.ToLower() == Column.ColumnName.ToLower());

    //--- get the datatype for this field in our system
    Type FieldDataType = Nullable.GetUnderlyingType(DestinationType.Property(ColumnMap.DestinationFieldName).PropertyType);

    //--- find the field data type and add to respective list
    switch (Type.GetTypeCode(FieldDataType))
    {
        case TypeCode.Int16:
        case TypeCode.Int32:
        case TypeCode.Int64: { IntColumns.Add(Column); break; }
        case TypeCode.Boolean: { BoolColumns.Add(Column); break; }
        case TypeCode.Double:
        case TypeCode.Decimal: { DecimalColumns.Add(Column); break; }
        case TypeCode.DateTime: { DateColumns.Add(Column); break; }
    }

    //--- add the mapping for the column on the BulkCopy object
    BulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(Column.ColumnName, ColumnMap.DestinationFieldName));
}

//--- loop through all rows and convert the values to data types that match our database's data type for that field
foreach (DataRow dr in dtData.Rows)
{
    //--- convert int values
    foreach (DataColumn IntCol in IntColumns)
        dr[IntCol] = Helpers.CleanNum(dr[IntCol].ToString());

    //--- convert decimal values
    foreach (DataColumn DecCol in DecimalColumns)
        dr[DecCol] = Helpers.CleanDecimal(dr[DecCol].ToString());

    //--- convert bool values
    foreach (DataColumn BoolCol in BoolColumns)
        dr[BoolCol] = Helpers.ConvertStringToBool(dr[BoolCol].ToString());

    //--- convert date values
    foreach (DataColumn DateCol in DateColumns)
        dr[DateCol] = dr[DateCol].ToString().Replace("T", " ");
}

try
{
    //--- do bulk insert
    BulkCopy.WriteToServer(dtData);
    transaction.Commit();
}
catch (Exception ex)
{
    transaction.Rollback();

    //--- handles error
    //--- this is where I need to find the row & column having an issue
}

此代码应设置目标字段的所有值的格式。在此错误的情况下,小数,清除该错误的函数将删除任何不是0-9或的字符。(小数点)。抛出错误的这个字段在数据库中是可以为空的。

2级异常具有以下错误:

代码语言:javascript
复制
Error Message: Failed to convert parameter value from a String to a Decimal.
Target Site: System.Object CoerceValue(System.Object, System.Data.SqlClient.MetaType, Boolean ByRef, Boolean ByRef, Boolean)

3级异常的错误如下:

代码语言:javascript
复制
Error Message: Input string was not in a correct format
Target Site: Void StringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Globalization.NumberFormatInfo, Boolean)

有没有人有什么想法需要修正?或者有什么想法来获取更多的信息?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2013-08-09 22:36:08

@Corey -它只是简单地去掉了所有无效字符。然而,你的评论让我想到了答案。

问题是我的数据库中的许多字段都是可以为空的。使用SqlBulkCopy时,不会将空字符串作为空值插入。因此,在我的字段不是varchar (bit、int、decimal、datetime等)的情况下,它试图插入一个空字符串,这对于该数据类型显然是无效的。

解决方案是修改我的循环,我将值验证为这个值(对每个非字符串的数据类型重复)

代码语言:javascript
复制
//--- convert decimal values
foreach (DataColumn DecCol in DecimalColumns)
{
     if(string.IsNullOrEmpty(dr[DecCol].ToString()))
          dr[DecCol] = null; //--- this had to be set to null, not empty
     else
          dr[DecCol] = Helpers.CleanDecimal(dr[DecCol].ToString());
}

在进行上述调整之后,插入的所有内容都没有问题。

票数 24
EN

Stack Overflow用户

发布于 2014-05-09 03:57:28

请使用SqlBulkCopyColumnMapping。

示例:

代码语言:javascript
复制
private void SaveFileToDatabase(string filePath)
{
    string strConnection = System.Configuration.ConfigurationManager.ConnectionStrings["MHMRA_TexMedEvsConnectionString"].ConnectionString.ToString();

    String excelConnString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0\"", filePath);
    //Create Connection to Excel work book 
    using (OleDbConnection excelConnection = new OleDbConnection(excelConnString))
    {
        //Create OleDbCommand to fetch data from Excel 
        using (OleDbCommand cmd = new OleDbCommand("Select * from [Crosswalk$]", excelConnection))
        {
            excelConnection.Open();
            using (OleDbDataReader dReader = cmd.ExecuteReader())
            {
                using (SqlBulkCopy sqlBulk = new SqlBulkCopy(strConnection))
                {
                    //Give your Destination table name 
                    sqlBulk.DestinationTableName = "PaySrcCrosswalk";

                    // this is a simpler alternative to explicit column mappings, if the column names are the same on both sides and data types match
                    foreach(DataColumn column in dt.Columns) {
                         s.ColumnMappings.Add(new SqlBulkCopyColumnMapping(column.ColumnName, column.ColumnName));
                     }
                   
                    sqlBulk.WriteToServer(dReader);
                }
            }
        }
    }
}  
票数 42
EN

Stack Overflow用户

发布于 2018-06-23 04:31:40

因为我不相信"Please use..." plus some random code that is unrelated to the question是一个好的答案,但我相信它的精神是正确的,所以我决定正确地回答这个问题。

使用Sql大容量复制时,它会尝试将输入数据直接与服务器上的数据对齐。

代码语言:javascript
复制
INSERT INTO [schema].[table] (col1, col2, col3) VALUES

因此,如果您给它列1、3和2,即使您的名称可能匹配(例如: col1、col3、col2)。它将像这样插入:

代码语言:javascript
复制
INSERT INTO [schema].[table] (col1, col2, col3) VALUES
                          ('col1', 'col3', 'col2')

Sql Bulk Insert必须确定列映射,这将是额外的工作和开销。所以它允许你选择...请确保Code和SQL Table列的顺序相同,或者显式声明按列名对齐。

因此,如果您的问题是列的未对齐,这可能是导致此错误的主要原因,则此答案适用于您。

TLDR

代码语言:javascript
复制
using System.Data;
//...
myDataTable.Columns.Cast<DataColumn>().ToList().ForEach(x => 
    bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(x.ColumnName, x.ColumnName)));

这将采用您正在尝试将其插入到创建的BulkCopy对象中的现有名称,它将显式地将DataTable映射到name。当然,如果由于某些原因,您决定以不同于SQL Server列的方式命名DataTable列...那是你的错。

票数 34
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18140012

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档