sqlbulkcopyスローSystem.formatexception writetoserverを実行するとき(datatable)
-
08-10-2019 - |
質問
現在、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:文字列は有効な日付として認識されませんでした。インデックス0で始まる未知の単語があります。
デバッグして、すべてのデータがデータテーブルに正しくロードされているのを確認しました。これが私の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
解決
私が最初に見た問題は、あなたが問題を抱えているということです RowID
桁;私はそれが現時点で1つの列であなたのデータを相殺しようとしていることを期待しています - それは 知らない あなたがそれを省略していること。マッピングを台無しにするか、(データテーブルで)追加することができます RowID
列(インデックス0) - ただし、SQLサーバーはIDINTERTを有効にしない限り、値を無視することに注意してください。
おそらく、より明示的なデータタイム変換を試してみてください:
row[j] = DateTime.ParseExact(data[j], "dd/MM/yyyy", CultureInfo.InvariantCulture);
それがDD/MMまたはMM/DDの場合、データからわからないので、それを微調整する必要があるかもしれないことに注意してください。
他のヒント
列がオフになっているという同様の問題があり、マッピングを定義したら問題ありません。
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);
}
また、リストを変換するために使用するデータテーブルコンバーター拡張機能のリストがあります。
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;
}
データファイルのフィールドはテーブルと一致していません。つまり、 DataVendorId
に RowId
あなたが変換できないので例外を引き起こす列 varchar(32)
に int
.
ID列をテーブルの端まで移動します。これで、バルクインサートはすべてのフィールドに一致することができます それまで 識別列に到達します。