通过 DLL 进行 Sybase 大容量复制:值不在预期范围内

本文关键字:范围内 进行 DLL Sybase 大容量 复制 通过 | 更新日期: 2023-09-27 18:37:07

我正在尝试使用 Sybase 安装(Sybase.AdoNet4.AseClient.dll版本 16.0.02)提供的 .net DLL 将数据从 Sql Server 迁移到 Sybase 16.0 数据库。

为了简单起见,我正在尝试从具有单个 INT 列的表中复制值

--source table (MSSQL)
CREATE TABLE [dbo].[TO_INTS](
    [TO_INT] [int] NULL,
    [TO_INT2] [int] NULL,
    [NAME] [varchar](50) NULL,
    [DT] [datetime] NULL
) ON [PRIMARY]

--target table (Sybase)
CREATE TABLE dbo.TO_INTS
    (
    FROM_INT INT NOT NULL
    )
    ON 'default'

我正在使用代码:

public void BulkCopyFromSqlServer(string sourceConnectionString, string targetConnectionString)
{
    SqlConnection sourceConnection = null;
    AseConnection targetConnection = new AseConnection(targetConnectionString);
    IDataReader dataSource=null;
    try
    {
        targetConnection.Open();
        MssqlCommand.GetDataReader(sourceConnectionString, out sourceConnection, out dataSource);  //see below
        AseBulkCopy blk = new AseBulkCopy(targetConnection);
        blk.BulkCopyTimeout = 1200;
        blk.DestinationTableName = "TO_INTS";
        blk.ColumnMappings.Clear();
        blk.ColumnMappings.Add(new AseBulkCopyColumnMapping(0,0));
        blk.WriteToServer(dataSource);  // System.ArgumentException thrown here.
        blk.Close();
    }
    catch (AseException ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {
        sourceConnection.Dispose(); 
        targetConnection.Dispose();             
    }
}
//MssqlCommand.GetDataReader(sourceConnectionString, out sourceConnection, out dataSource):
public static void GetDataReader(string sqlServerConnectionString, out SqlConnection conn, out IDataReader reader)
{
    conn = new SqlConnection(sqlServerConnectionString);
    conn.Open();
    SqlCommand cmd = new SqlCommand("select * from TO_INTS", conn);
    cmd.CommandTimeout = 60;
    reader = cmd.ExecuteReader();
}

当调用WriteToServer()时,会抛出一个系统参数异常,并带有消息"Value does not fall within the expected range"。堆栈跟踪很有趣,因为它看起来 Sybase DLL 无法使用映射中提供的索引解析数据库列名称,这似乎很奇怪:

   at Sybase.Data.AseClient.AseBulkCopy.GetDBColName(String clientColName, Int32 clientColInx)
   at Sybase.Data.AseClient.AseBulkCopy.GenerateInsertCmdByReaderMetaInfo(DataTable rowFmt)
   at Sybase.Data.AseClient.AseBulkCopy.WriteToServer(IDataReader reader)

我对Sybase> Sql Server遵循了相同的过程(几乎是逐行的,但切换了相关的DLL),并且这有效。

我错过了一些明显的东西吗?

通过 DLL 进行 Sybase 大容量复制:值不在预期范围内

看起来我已经解决了这个问题。

我的代码中有两个错误。

出现初始错误是因为我不知道如何将 EnableBulkLoad 参数放在连接字符串中。我的工作连接字符串如下所示:

string SybaseConnectionString = "Data Source=server1;Initial Catalog=mydb;persist security info=False;User Id=sa;Password=password1;Port=5000;EnableBulkLoad=2" 

添加后,会引发第二个错误:

Bad row data received from the client while bulk copying into object 2080007410 partition 2080007410 in database 6. Received a row of length 11 whilst maximum or expected row length is 6.

出现这种情况是因为表名是使用以下方法设置的:

blk.DestinationTableName = "TO_INTS";

当它应该是:

blk.DestinationTableName = "dbo.TO_INTS";

一旦我添加了所有者,然后批量复制就可以工作了。

对于 ref,现在我已经让它工作了,我能够在具有不同名称的表之间完成 WriteToServer 调用。此外,列名在每个表中都是唯一的,即源 Sql Server 表:

CREATE TABLE [dbo].[SOURCE_INTS](
    [TO_INT] [int] NULL,
    [TO_INT2] [int] NULL,
    [NAME] [varchar](50) NULL,
    [DT] [datetime] NULL
) ON [PRIMARY]

目标系统表:

CREATE TABLE dbo.TO_INTS
    (
    THE_STRING VARCHAR(50) NOT NULL,
    THE_INT INT NOT NULL,
    THE_DT DATETIME NOT NULL
    )
    LOCK ALLPAGES
    ON 'default'
GO

您还会注意到顺序不同,但WriteToServer通过映射处理得很好:

blk.ColumnMappings.Add(new AseBulkCopyColumnMapping(2, 0)); //string col
blk.ColumnMappings.Add(new AseBulkCopyColumnMapping(1, 1)); //int col
blk.ColumnMappings.Add(new AseBulkCopyColumnMapping(3, 2)); //datetime col

如果您需要有关 Sybase Data Provider for C# 的更多信息,请尝试 Sybase Books Online

希望这对某人有所帮助。

除了这个之外,我没有任何直接的观察结果:MS SQL中的源表与ASE中的目标表在两个方面不同:

  1. 它的列较少,并且

  2. ASE 中的列
  3. 名与 MS SQL 中的列名不同。

如果不了解此处发生的全部范围和上下文,不难想象源表和目标表之间会发生不匹配。