Ric*_*tts 45 c# datatable sqlbulkcopy
我在尝试从DataTable执行SqlBulkCopy时遇到此异常.
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)
Run Code Online (Sandbox Code Playgroud)
我理解错误说的是什么,但我怎样才能获得更多信息,例如行/字段正在发生?数据表由第三方填充,最多可包含200列和最多10k行.返回的列取决于发送给第三方的请求.所有的数据表列是字符串类型.我的数据库中的列不是所有varchar,因此,在执行插入之前,我使用以下代码格式化数据表值(删除非重要代码):
//--- 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
}
Run Code Online (Sandbox Code Playgroud)
此代码应格式化其目标字段的所有值.在这个错误的情况下,十进制,清除它的函数将删除任何不是0-9或的字符.(小数点).抛出错误的该字段在数据库中可以为空.
2级异常有这个错误:
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)
Run Code Online (Sandbox Code Playgroud)
并且3级异常有这个错误:
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)
Run Code Online (Sandbox Code Playgroud)
有没有人有任何想法要修复?或任何想要获得更多信息的想法?
小智 33
请使用SqlBulkCopyColumnMapping.
例:
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";
SqlBulkCopyColumnMapping AdmissionPaySrcID=new SqlBulkCopyColumnMapping("AdmissionPaySrcID","AdmissionPaySrcID");
sqlBulk.ColumnMappings.Add(AdmissionPaySrcID);
SqlBulkCopyColumnMapping TMHP_Detail = new SqlBulkCopyColumnMapping("TMHP_Detail", "TMHP_Detail");
sqlBulk.ColumnMappings.Add(TMHP_Detail);
SqlBulkCopyColumnMapping PaySrcType = new SqlBulkCopyColumnMapping("PaySrcType", "PaySrcType");
sqlBulk.ColumnMappings.Add(PaySrcType);
SqlBulkCopyColumnMapping AgencyID = new SqlBulkCopyColumnMapping("AgencyID", "AgencyID");
sqlBulk.ColumnMappings.Add(AgencyID);
SqlBulkCopyColumnMapping CountyCode = new SqlBulkCopyColumnMapping("CountyCode", "CountyCode");
sqlBulk.ColumnMappings.Add(CountyCode);
SqlBulkCopyColumnMapping EntityID = new SqlBulkCopyColumnMapping("EntityID", "EntityID");
sqlBulk.ColumnMappings.Add(EntityID);
sqlBulk.WriteToServer(dReader);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ric*_*tts 22
@Corey - 它只是删除所有无效字符.但是,你的评论让我想到了答案.
问题是我的数据库中的许多字段都可以为空.使用SqlBulkCopy时,不会将空字符串作为空值插入.所以在我的字段不是varchar(bit,int,decimal,datetime等)的情况下,它试图插入一个空字符串,这显然对该数据类型无效.
解决方案是修改我的循环,我在其中验证值(对于非字符串的每个数据类型重复)
//--- 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());
}
Run Code Online (Sandbox Code Playgroud)
完成上述调整后,所有内容都会毫无问题地插入.
Sua*_*ere 16
既然我不相信"Please use..." plus some random code that is unrelated to the question是一个好的答案,但我相信精神是正确的,我决定正确回答这个问题.
当您使用Sql批量复制时,它会尝试将输入数据直接与服务器上的数据对齐.因此,它需要服务器表并执行类似于此的SQL语句:
INSERT INTO [schema].[table] (col1, col2, col3) VALUES
Run Code Online (Sandbox Code Playgroud)
因此,如果您给它第1,3和2列,即使您的名字可能匹配(例如:col1,col3,col2).它会像这样插入:
INSERT INTO [schema].[table] (col1, col2, col3) VALUES
('col1', 'col3', 'col2')
Run Code Online (Sandbox Code Playgroud)
Sql批量插入必须确定列映射是额外的工作和开销.因此,它允许您选择...确保您的代码和SQL表列的顺序相同,或者显式声明按列名对齐.
因此,如果您的问题是列的错误对齐,这可能是此错误的主要原因,那么这个答案适合您.
using System.Data;
//...
myDataTable.Columns.Cast<DataColumn>().ToList().ForEach(x =>
bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(x.ColumnName, x.ColumnName)));
Run Code Online (Sandbox Code Playgroud)
这将采用您现有的DataTable,您尝试将其插入到创建的BulkCopy对象中,它将只显式地将name映射到name.当然,如果由于某种原因,您决定以不同于SQL Server列的方式命名您的DataTable列...那就在您身上.
小智 5
不会是每个人的解决方案,但它适合我:
所以,我遇到了这个确切的问题。我似乎遇到的问题是,当我的 DataTable 没有 ID 列,但目标目的地有一个带有主键的列时。
当我调整我的 DataTable 以使其具有 id 时,副本工作得很好。
在我的场景中,Id 列对于主键来说并不是非常重要,因此我从目标目标表中删除了该列,并且 SqlBulkCopy 可以正常工作。
| 归档时间: |
|
| 查看次数: |
98026 次 |
| 最近记录: |