SqlBulkCopy error: The locale id '0' of the source column .. and the locale id '1033' of the destination column .. do not match
SqlBulkCopy error: The locale id '0' of the source column .. and the locale id '1033' of the destination column .. do not match
我知道有类似的问题,但我仍然没有找到这个问题的答案。
我的设置如下。
来源table:
目的地table:
SqlBulkCopy 调用:
using (var destination = new SqlConnection(builderDestinationConnectionString.ConnectionString))
{
try
{
destination.Open();
}
catch (Exception exception)
{
...
}
using (var bulkCopy = new SqlBulkCopy(myConnectionString))
{
var cancellationTokenSource = new CancellationToken();
bulkCopy.DestinationTableName = destinationTableName;
bulkCopy.BatchSize = batchSize ?? GlobalContext.Configuration.BulkCopyBatchSize;
bulkCopy.BulkCopyTimeout = GlobalContext.Configuration.BulkCopyTimeout;
bulkCopy.EnableStreaming = true;
bulkCopy.NotifyAfter = GlobalContext.Configuration.BulkCopyNotifyLimit;
bulkCopy.SqlRowsCopied += new SqlRowsCopiedEventHandler((sender, args) => myContext.Log.Info($"{args.RowsCopied} rows copied to {destinationTableName}"));
try
{
await bulkCopy
.WriteToServerAsync(reader, cancellationTokenSource)
.ConfigureAwait(false);
}
catch (Exception exception)
{
...
}
}
}
工作场景:
如果我的 reader 执行查询 SELECT * FROM BulkTable sqlBulkCopy 工作正常。
非工作场景:
这个逻辑必须是通用的,有时我使用 select 查询连接不同的 table,因此我不需要 Id .因此我尝试了这个查询而不是 SELECT *:
SELECT CONVERT([VARCHAR](50), [SomeString]) AS [SomeString]
,CONVERT([DATETIME], [SomeDate]) AS [SomeDate]
,CONVERT([INT], [SomeInt]) AS [SomeInt]
,CONVERT([FLOAT], [SomeFloat]) AS [SomeFloat]
,CONVERT([TEXT], [SomeText]) AS [SomeText]
,CONVERT([DECIMAL](18, 8), [SomeDecimal]) AS [SomeDecimal]
FROM BulkTable
错误是:
The locale id '0' of the source column 'SomeDate' and the locale id '1033' of the destination column 'SomeString' do not match
我不是故意在 SqlBulkCopy 中使用 KeepIdentity,这样目标 table 可以生成自己的身份,但仍然没有。
我不想在 BulkCopy 中使用 ColumnMappings,因为如前所述,此逻辑必须保持通用以允许不同的 sources/destinations 和列。
在您的错误中,您在源和目标中引用了 2 个不同的列名称,因此当您删除 ID 时会出现列对齐问题。
列对齐:列在位置上进行映射,在您的非工作场景中,当您删除 ID 时,数据只是左移一列。
导致 somestring -> id,然后 somedate -> somestring。
通常它会导致类型转换错误,但在这里它似乎首先检测到列之间的语言环境不匹配。
您可以:从目标中删除 ID 或填充虚拟 int 作为 select 中的第一列(或使用其他一些 rownum 函数)。
或者只是拉过 ID 并忽略它(如果由于涉及多个源表而可能包含重复值,请重命名目标列以避免混淆)。
我知道有类似的问题,但我仍然没有找到这个问题的答案。 我的设置如下。
来源table:
目的地table:
SqlBulkCopy 调用:
using (var destination = new SqlConnection(builderDestinationConnectionString.ConnectionString))
{
try
{
destination.Open();
}
catch (Exception exception)
{
...
}
using (var bulkCopy = new SqlBulkCopy(myConnectionString))
{
var cancellationTokenSource = new CancellationToken();
bulkCopy.DestinationTableName = destinationTableName;
bulkCopy.BatchSize = batchSize ?? GlobalContext.Configuration.BulkCopyBatchSize;
bulkCopy.BulkCopyTimeout = GlobalContext.Configuration.BulkCopyTimeout;
bulkCopy.EnableStreaming = true;
bulkCopy.NotifyAfter = GlobalContext.Configuration.BulkCopyNotifyLimit;
bulkCopy.SqlRowsCopied += new SqlRowsCopiedEventHandler((sender, args) => myContext.Log.Info($"{args.RowsCopied} rows copied to {destinationTableName}"));
try
{
await bulkCopy
.WriteToServerAsync(reader, cancellationTokenSource)
.ConfigureAwait(false);
}
catch (Exception exception)
{
...
}
}
}
工作场景:
如果我的 reader 执行查询 SELECT * FROM BulkTable sqlBulkCopy 工作正常。
非工作场景:
这个逻辑必须是通用的,有时我使用 select 查询连接不同的 table,因此我不需要 Id .因此我尝试了这个查询而不是 SELECT *:
SELECT CONVERT([VARCHAR](50), [SomeString]) AS [SomeString]
,CONVERT([DATETIME], [SomeDate]) AS [SomeDate]
,CONVERT([INT], [SomeInt]) AS [SomeInt]
,CONVERT([FLOAT], [SomeFloat]) AS [SomeFloat]
,CONVERT([TEXT], [SomeText]) AS [SomeText]
,CONVERT([DECIMAL](18, 8), [SomeDecimal]) AS [SomeDecimal]
FROM BulkTable
错误是:
The locale id '0' of the source column 'SomeDate' and the locale id '1033' of the destination column 'SomeString' do not match
我不是故意在 SqlBulkCopy 中使用 KeepIdentity,这样目标 table 可以生成自己的身份,但仍然没有。
我不想在 BulkCopy 中使用 ColumnMappings,因为如前所述,此逻辑必须保持通用以允许不同的 sources/destinations 和列。
在您的错误中,您在源和目标中引用了 2 个不同的列名称,因此当您删除 ID 时会出现列对齐问题。
列对齐:列在位置上进行映射,在您的非工作场景中,当您删除 ID 时,数据只是左移一列。
导致 somestring -> id,然后 somedate -> somestring。
通常它会导致类型转换错误,但在这里它似乎首先检测到列之间的语言环境不匹配。
您可以:从目标中删除 ID 或填充虚拟 int 作为 select 中的第一列(或使用其他一些 rownum 函数)。 或者只是拉过 ID 并忽略它(如果由于涉及多个源表而可能包含重复值,请重命名目标列以避免混淆)。