c# 4.0 - 奇怪的"链接服务器"(null)"的 OLE DB 提供程序'STREAM'返回了列 '[!批量插入]。值"错误



使用的软件:Windows 7 64位旗舰版、.Net 4、SQL Server 2008 R2。

选择@@version返回:

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1617.0 (X64)   Apr 22 2011 19:23:43   Copyright (c) Microsoft Corporation  Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor) 

要复制,并假设您有一个本地sql server 2008 R2实例,请将以下代码粘贴到linqpad中,并将其作为程序运行。

它爆炸了:

链接服务器"(null)"的OLE DB访问接口"STREAM"为列"[!BulkInsert].Value"返回了无效数据。

void Main()
{
  SqlConnection cn = new SqlConnection("data source=localhost;Integrated Security=SSPI;initial catalog=tempdb;Connect Timeout=180;");
  cn.Open();
  IList<decimal> list = new List<decimal>() {-8m, 8m};
  decimal result = list.Sum(x => x);
  Console.WriteLine(result == 0);
  string tableName = "#test";
  CreateTemporaryTable(cn, tableName,
        String.Format(@"
          create table {0} (
            Value sql_variant
         );
       ", tableName));
  SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(cn);
  sqlBulkCopy.DestinationTableName = tableName;       
  DataTable dt = new DataTable();
  dt.Columns.Add("Value", typeof(object));
  dt.Rows.Add(result);
  sqlBulkCopy.WriteToServer(dt);
  sqlBulkCopy.Close();
  cn.Close();
}
// Define other methods and classes here

public static void CreateTemporaryTable(SqlConnection cn, string destinationTableName, string createTableStatement)
{
  string objectIdValue = (destinationTableName.StartsWith("#") ? "tempdb.." : "") + destinationTableName;
  string sql = String.Format(@" 
    if (object_id (N'{0}', N'U') is not null)
      begin
        drop table {1};
      end;
      {2}    
      ", objectIdValue, destinationTableName, createTableStatement);
//      Console.WriteLine(sql);
  SqlCommand cmd = new SqlCommand(sql, cn);
  try
  {
    cmd.ExecuteNonQuery();
  }
  finally
  {
    cmd.Dispose();
  }
}

我可能会和微软一起创建一个案例,但我很好奇以前是否有人看到过这个,以及是否有什么解决办法。似乎并不是所有的零都是相等的。

只是更新:

我在微软开了一个案子。他们花了将近2个月的时间才想出一些模糊的未记录的dbcc标志,该标志关闭了对通过大容量复制到变量列中的值的验证。该案件在不同的团队之间来回切换(支持由印度私人承包商提供),他们从未找到根本问题,我认为这与以下行产生的价值以及批量复制代码如何处理有关:

  IList<decimal> list = new List<decimal>() {-8m, 8m};
  decimal result = list.Sum(x => x);

所以,最后,这是令人失望的,我放弃了,因为这是一种罕见的情况。

如果列'value'的数据类型是float,那么可能的问题是发送double。NaN到sql server,这是它不喜欢的。

请注意,一个类似双重通话。TryParse("NaN",out dv)将愉快地返回true并将dv设置为双倍。NaN

希望这能有所帮助,K.

如果double.NaN在表中,则会引发此错误,因此请转换为null

我使用了这种扩展方法来解决这个问题。

要使用,请将.MyToNullIfNan()附加到任何doubledouble?,如果NaN,它将生成一个double?,即null

public static class MyToNullIfNanExtension
{
    public static double? MyToNullIfNan(this double? result)
    {
        if (result.HasValue)
        {
            if (double.IsNaN(result.Value) || double.IsInfinity(result.Value))
            {
                return null;
            }
        }
        return result;
    }
    public static double? MyToNullIfNan(this double result)
    {
        if (double.IsNaN(result) || double.IsInfinity(result))
        {
            return null;
        }
        return result;
    }
}

我最终使用的Microsoft指示的解决方案是使用这个未记录的标志:DBCC TRACEON(7307,-1)。您可以在连接级别或服务器级别启用它。

当列映射中的字段中的数据类型不一致时,往往会发生此错误。

例如,当字符串列映射到uniqueidentifier字段时,即使在验证不存在任何可能导致guid出现问题的空/null值之后,也可能发生此错误。

bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("GuidColumn", "SqlGuidColumn"));

这两者都需要在键入时完全匹配,以免您从OLEDB中得到奇怪的错误!

大容量复制非常适合将大型数据集写入表中的高I/O操作。。。然而,它并不能很好地说明为什么一个特定的行在整个集合中失败。正是对行级操作的忽略使其执行速度大大快于逐行执行。

相关内容

最新更新