2009-06-21 25 views
15

Estoy tratando de insertar por lotes datos en SQL 2008 usando SqlBulkCopy.Error al insertar datos usando SqlBulkCopy

Aquí está mi mesa:

IF OBJECT_ID(N'statement', N'U') IS NOT NULL 
DROP TABLE [statement] 
GO 
CREATE TABLE [statement](
    [ID] INT IDENTITY(1, 1) NOT NULL, 
    [date] DATE NOT NULL DEFAULT GETDATE(), 
    [amount] DECIMAL(14,2) NOT NULL, 
CONSTRAINT [PK_statement] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

Aquí está mi código:

private DataTable GetTable() 
{ 
    var list = new List<DataColumn>(); 
    list.Add(new DataColumn("amount", typeof(SqlDecimal))); 
    list.Add(new DataColumn("date", typeof(SqlDateTime))); 

    var table = new DataTable("statement"); 
    table.Columns.AddRange(list.ToArray()); 

    var row = table.NewRow(); 
    row["amount"] = (SqlDecimal)myObj.Amount; // decimal Amount { get; set; } 
    row["date"] = (SqlDateTime)myObj.Date; // DateTime Date { get; set } 
    table.Rows.Add(row); 

    return table; 
} 

private void WriteData() 
{ 
    using (var bulk = new SqlBulkCopy(strConnection, SqlBulkCopyOptions.KeepIdentity & SqlBulkCopyOptions.KeepNulls)) 
    { 
     //table.Columns.ForEach(c => bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName))); 
     bulk.BatchSize = 25; 
     bulk.DestinationTableName = "statement"; 
     bulk.WriteToServer(GetTable()); // a table from GetTable() 
    } 
} 

así que estoy de error:

The given value of type SqlDateTime from the data source cannot be converted to type date of the specified target column.

Por qué ?? ¿Cómo puedo arreglar eso? ¡Ayudame por favor!

Respuesta

19

Usando el script de tabla original, el siguiente código funciona.

private static DataTable GetTable() 
{ 
    var list = new List<DataColumn>(); 
    list.Add(new DataColumn("amount", typeof(Double))); 
    list.Add(new DataColumn("date", typeof(DateTime))); 
    var table = new DataTable("statement"); 
    table.Columns.AddRange(list.ToArray()); 

    var row = table.NewRow(); 
    row["amount"] = 1.2d; 
    row["date"] = DateTime.Now.Date; 

    table.Rows.Add(row); 
    return table; 
} 
private static void WriteData() 
{ 
    string strConnection = "Server=(local);Database=ScratchDb;Trusted_Connection=True;"; 
    using (var bulk = new SqlBulkCopy(strConnection, SqlBulkCopyOptions.KeepIdentity & SqlBulkCopyOptions.KeepNulls)) 
    { 
     bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping("amount", "amount")); 
     bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping("date", "date")); 
     bulk.BatchSize = 25; 
     bulk.DestinationTableName = "statement"; 
     bulk.WriteToServer(GetTable()); 
    } 
} 

Como ya ha declarado Amal, necesita las asignaciones de columna debido a la columna Identidad.

+5

¿No debería ser eso "SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls"? – rusty

6

El tipo de fecha de SQL es diferente al tipo de fecha y hora de SQL. Creo que la columna de fecha en su tabla debe ser del tipo DateTime, en función de la forma en que la está utilizando.

SQL Date Type
SQL DateTime type

Actualización:

Creo que la respuesta de Marc debería funcionar, pero es probable que tenga que especificar los SqlBulkCopyColumnMappings de su DataTable origen al destino, de lo contrario podría estar recibiendo el mal mapeo porque la estructura de su tabla de entrada no coincide exactamente con la tabla de salida, es decir, el orden de la fecha y las columnas de fila intercambiadas.

por ejemplo

var amount = new SqlBulkCopyColumnMapping("amount", "amount"); 
var date = new SqlBulkCopyColumnMapping("date", "date"); 
bulk.ColumnMappings.Add(amount); 
bulk.ColumnMappings.Add(date); 
+0

Sí, entiendo que sean diferentes. ¿Pero cómo puedo usar exactamente DbType.Date si solo DbType.DateTime/SqlDateTime/DateTime está en todas partes ?! – abatishchev

+0

Puede usar el "DATETIME" más utilizado en la tabla temporal que utiliza para la carga masiva, y luego usar "DATE" en la tabla de datos "real". Puede asignar fácilmente un DateTime a una fecha en una instrucción T-SQL. –

2

SqlDateTime representa el tipo original datetime. ¿Has intentado simplemente usar el tipo 0NET de DateTime en el DataTable? Espero que pueda convertir esto a los tipos de TSQL datetime o date. Omitir decimal en lugar de SqlDecimal.

+0

Si uso typeof (Double) obtendré un error: "El valor dado de tipo SqlString de la fuente de datos no se puede convertir a tipo decimal de la columna de destino especificada". ¡Los mismos errores con typeof (DateTime)! Y no puedo usar typeof (Decimal) porque la columna apropiada representa dinero y requiere 2 dígitos decimales ... – abatishchev

Cuestiones relacionadas