Ошибка вставки данных с помощью SqlBulkCopy

Я пытаюсь пакетно вставить данные в SQL 2008, используя SqlBulkCopy.

Вот моя таблица:

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

Вот мой код:

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() 
    }
}

Итак, я получаю сообщение об ошибке:

Заданное значение типа SqlDateTime из источника данных не может быть преобразовано в тип date указанного целевого столбца.

Почему?? Как я могу это исправить? Помоги мне, пожалуйста!


person abatishchev    schedule 21.06.2009    source источник


Ответы (3)


Используя исходный сценарий таблицы, работает следующий код.

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());
    }
}

Как уже сказал Амаль, вам нужны сопоставления столбцов из-за столбца Identity.

person Kim Major    schedule 21.06.2009
comment
Разве это не должно быть SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls? - person rusty; 18.08.2010

Тип SQL Date отличается от типа SQL DateTime. Я думаю, что столбец даты в вашей таблице должен иметь тип DateTime, в зависимости от того, как вы его используете.

Тип даты SQL
Тип SQL DateTime

Обновлять:

Я думаю, что ответ Марка должен работать, но вам, вероятно, нужно указать SqlBulkCopyColumnMappings из исходного DataTable в место назначения, иначе это может привести к неправильному сопоставлению, поскольку структура вашей входной таблицы не соответствует выходной таблице точно, т.е. порядок даты и столбцы строки поменялись местами.

eg

var amount = new SqlBulkCopyColumnMapping("amount", "amount");
var date = new SqlBulkCopyColumnMapping("date", "date");
bulk.ColumnMappings.Add(amount);
bulk.ColumnMappings.Add(date);
person Amal Sirisena    schedule 21.06.2009
comment
Да, я понимаю, что они разные. Но как мне использовать именно DbType.Date, если везде только DbType.DateTime/SqlDateTime/DateTime?! - person abatishchev; 21.06.2009
comment
Вы можете использовать более широко используемый DATETIME во временной таблице, которую вы используете для массовой загрузки, а затем использовать фактическую DATE в таблице реальных данных. Вы можете легко присвоить DateTime Date в операторе T-SQL. - person marc_s; 21.06.2009

SqlDateTime представляет исходный тип datetime. Вы пытались просто использовать тип DateTime .NET в DataTable? Я надеюсь, что он сможет преобразовать это в типы TSQL datetime или date. То же самое decimal вместо SqlDecimal.

person Marc Gravell    schedule 21.06.2009
comment
Если я использую typeof(Double), то получу ошибку: заданное значение типа SqlString из источника данных не может быть преобразовано в десятичный тип указанного целевого столбца. Те же ошибки с typeof(DateTime)! И я не могу использовать typeof(Decimal), потому что соответствующий столбец представляет деньги и требует 2 десятичных цифры. - person abatishchev; 21.06.2009