【问题标题】:SqlBulkCopy throws System.FormatException when running WriteToServer(DataTable)SqlBulkCopy 在运行 WriteToServer(DataTable) 时抛出 System.FormatException
【发布时间】:2010-11-12 06:24:15
【问题描述】:

目前我正在编写一种从 CSV 文件中读取数据并导入 SQL 表的方法。

        DataTable dt = new DataTable();
        String line = null;
        int i = 0;

        while ((line = reader.ReadLine()) != null)
        {
            String[] data = line.Split(',');
            if (data.Length > 0)
            {
                if (i == 0)
                {
                    foreach (object item in data)
                    {
                        DataColumn c = new DataColumn(Convert.ToString(item));
                        if (Convert.ToString(item).Contains("DATE"))
                        {
                            c.DataType = System.Type.GetType("System.DateTime");
                        }
                        else { c.DataType = System.Type.GetType("System.String"); }
                        dt.Columns.Add(c);
                    }
                    i++;
                }
                else
                {
                    DataRow row = dt.NewRow();
                    for (int j = 0; j < data.Length; j++)
                    {
                        if (dt.Columns[j].DataType == System.Type.GetType("System.DateTime"))
                        {
                            row[j] = Convert.ToDateTime(data[j]);
                        }
                        else
                        {
                            row[j] = data[j];
                        }
                    }
                    dt.Rows.Add(row);
                }
            }
        }
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[Constant.CONNECTION_STRING_NAME].ConnectionString);
        SqlBulkCopy s = new SqlBulkCopy(con);
        s.DestinationTableName = "abc";
        con.Open();
        s.WriteToServer(dt);

运行该方法时的问题,s.WriteToServer(dt);处总是抛出异常;说

System.FormatException:字符串未被识别为有效的 DateTime。从索引 0 开始有一个未知单词。

我调试并看到所有数据都正确加载到 DataTable 中。 这是我的 CSV 文件中的数据行示例

DATA_VENDOR_ID,DATA_VENDOR_SUB_ID,DATA_VENDOR_CLIENT_ID,DATA_VENDOR_ACTIVITY_CODE,ACTIVITY_NAME,EFFECTIVE_DATE,ACTIVITY_LEVEL1,ACTIVITY_LEVEL2,ACTIVITY_LEVEL3,ACTIVITY_LEVEL4,ACTIVITY_LEVEL5,PARTICIPANT_ID,DATA_VENDOR_ALT_ID,FILE_CREATION_DATE,INC_VALUE    
V01,,22097,ABCD01,Physical Activity,10/01/2010,Entertain Kiosk,ABCD - EFG 54,30,,AB01,W1234567891,,08/07/2006,100

还有我的 SQL 表架构:

RowID   int Unique/AutoIncrement
DataVendorId    varchar(32) 
DataVendorSubId varchar(32) 
DataVendorClientId  varchar(32) 
DataVendorActivityCode  varchar(32) 
ActivityName    varchar(64) 
EffectiveDate   datetime    
ActivityLevel1  varchar(253)    
ActivityLevel2  varchar(253)    
ActivityLevel3  varchar(253)    
ActivityLevel4  varchar(253)    
ActivityLevel5  varchar(253)    
ParticipantID   varchar(32) 
DataVendorAltId varchar(32) 
FileCreationDate    datetime    
IncValue    varchar(5)  
CreatedDate datetime    optional/allow null
ModifiedDate    datetime    optional/allow null

【问题讨论】:

  • 顺便说一句,使用typeof(string) 比使用System.Type.GetType("System.String") 更有效 - 同上typeof(DateTime)
  • 非常感谢您的推荐 :)

标签: c# sql csv sqlbulkcopy formatexception


【解决方案1】:

我看到的第一个问题是您将遇到RowID 列的问题;我希望它目前正试图将您的数据偏移一列 - 它不知道您正在忽略它。您可以弄乱映射,或者(在您的数据表中)添加一个 RowID 列(在索引 0 处) - 但请注意,除非您启用标识插入,否则 SQL Server 将忽略这些值。

也许尝试更明确的日期时间转换:

row[j] = DateTime.ParseExact(data[j], "dd/MM/yyyy", CultureInfo.InvariantCulture);

请注意,我无法从数据中判断是 dd/MM 还是 MM/dd,因此您可能需要对其进行调整。

【讨论】:

  • 你说得对,我尝试为 RowID 添加一个虚拟列,它成功了!
【解决方案2】:

我在列关闭的情况下遇到了类似的问题,一旦我定义了映射,就没有问题了:

using (SqlBulkCopy sbc = new SqlBulkCopy(ConfigurationManager.ConnectionStrings["SQLDatabase"].ConnectionString, SqlBulkCopyOptions.KeepIdentity))
            {
                sbc.DestinationTableName = "DestinationTable";
                sbc.ColumnMappings.Add("foo", "bar");
                sbc.ColumnMappings.Add("hello", "world");
                sbc.ColumnMappings.Add("col1", "col2");
                sbc.WriteToServer(data);
            }

另外,我有一个 List to DataTable 转换器扩展,用于转换我的 List。

public static DataTable ToDataTable<T>(this IEnumerable<T> data)
        {
            PropertyDescriptorCollection properties =
                TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            foreach (PropertyDescriptor prop in properties)
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            foreach (T item in data)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                    row[prop.Name] = GetDataValue(prop.GetValue(item));
                table.Rows.Add(row);
            }
            return table;
        }

GetDataValue() 方法清理我的 MinValue 日期等数据:

private static object GetDataValue(object value)
        {
            if (value == null || (value.GetType() == typeof(DateTime) && Convert.ToDateTime(value) == DateTime.MinValue) || (value.GetType() == typeof(DateTime) && Convert.ToDateTime(value) < Convert.ToDateTime("01/01/1753")))
            {
                return DBNull.Value;
            }

            return value;
        }

【讨论】:

    【解决方案3】:

    您的数据文件中的字段与表不匹配,即您试图将DataVendorId 插入到RowId 列中,这会导致异常,因为您无法将varchar(32) 转换为int .

    将您的身份列移到表格的末尾。现在批量插入将能够匹配所有字段直到它到达识别列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      相关资源
      最近更新 更多