C# 使用SqlBulkCopy插入数据时出错

C# 使用SqlBulkCopy插入数据时出错,c#,sql-server,datetime,ado.net,sqlbulkcopy,C#,Sql Server,Datetime,Ado.net,Sqlbulkcopy,我正在尝试使用SqlBulkCopy将数据批量插入SQL2008 这是我的桌子: 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,

我正在尝试使用
SqlBulkCopy
将数据批量插入SQL2008

这是我的桌子:

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() 
    }
}
私有数据表GetTable()
{
var list=新列表();
添加(新数据列(“金额”,类型(SqlDecimal)));
添加(新数据列(“日期”,typeof(SqlDateTime)));
var表=新数据表(“报表”);
table.Columns.AddRange(list.ToArray());
var row=table.NewRow();
行[“金额”]=(SqlDecimal)myObj.amount;//十进制金额{get;set;}
行[“日期”]=(SqlDateTime)myObj.date;//日期时间日期{get;set}
table.Rows.Add(行);
返回表;
}
私有无效写入数据()
{
使用(var bulk=new SqlBulkCopy(strConnection、SqlBulkCopyOptions.KeepIdentity和SqlBulkCopyOptions.KeepNulls))
{
//table.Columns.ForEach(c=>bulk.ColumnMappings.Add(新的SqlBulkCopyColumnMapping(c.ColumnName,c.ColumnName));
bulk.BatchSize=25;
bulk.DestinationTableName=“语句”;
bulk.WriteToServer(GetTable());//GetTable()中的表
}
}
所以我得到了一个错误:

数据源中类型为
SqlDateTime
的给定值无法转换为指定目标列的类型
date


为什么??我怎样才能解决这个问题?请帮帮我

SQL日期类型与SQL日期时间类型不同。我认为表中的date列需要是DateTime类型,这取决于您使用它的方式


更新:

我认为Marc的答案应该可行,但您可能需要指定从源DataTable到目标DataTable的SqlBulkCopyColumnMappings,否则可能会导致映射错误,因为输入表的结构与输出表不完全匹配,即日期和行列交换的顺序

乙二醇


SqlDateTime
表示原始的
datetime
类型。您是否尝试过只使用
数据表
中的
日期时间
.NET类型?我希望它可以将其转换为TSQL
datetime
date
类型。同上
decimal
使用原始表脚本代替
SqlDecimal

,下面的代码可以工作

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());
    }
}
private静态数据表GetTable()
{
var list=新列表();
添加(新数据列(“金额”,类型(双));
添加(新数据列(“日期”,类型(日期时间)));
var表=新数据表(“报表”);
table.Columns.AddRange(list.ToArray());
var row=table.NewRow();
行[“金额”]=1.2d;
行[“日期”]=DateTime.Now.date;
table.Rows.Add(行);
返回表;
}
私有静态void WriteData()
{
string strConnection=“Server=(local);Database=ScratchDb;Trusted_Connection=True;”;
使用(var bulk=new SqlBulkCopy(strConnection、SqlBulkCopyOptions.KeepIdentity和SqlBulkCopyOptions.KeepNulls))
{
Add(新的SqlBulkCopyColumnMapping(“amount”、“amount”);
添加(新的SqlBulkCopyColumnMapping(“日期”);
bulk.BatchSize=25;
bulk.DestinationTableName=“语句”;
WriteToServer(GetTable());
}
}

正如Amal所述,由于标识列的原因,您需要列映射。

如果我使用typeof(Double),则会出现错误:“数据源中类型为SqlString的给定值无法转换为指定目标列的类型decimal”。typeof(DateTime)也有同样的错误!我不能使用typeof(Decimal),因为适当的列表示货币,需要2个十进制数字。是的,我知道它们是不同的。但是,如果到处都是DbType.DateTime/SqlDateTime/DateTime,我怎么能准确地使用DbType.Date?!您可以在用于批量加载的临时表中使用更广泛使用的“DATETIME”,然后在“real”数据表中使用实际的“DATE”。您可以轻松地在T-SQL语句中为日期分配日期时间。这不应该是“SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls”吗?
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());
    }
}