Массовое копирование Sybase через DLL: значение не соответствует ожидаемому диапазону

Я пытаюсь перенести данные с Sql Server в базу данных Sybase 16.0 с помощью .net DLL, поставляемых с установкой Sybase (Sybase.AdoNet4.AseClient.dll версии 16.0.02).

Чтобы упростить задачу, я пытаюсь скопировать значения из таблицы с одним столбцом 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]

to

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

Исключение System.ArgumentException возникает, когда 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), и это работает.

Я упускаю что-то очевидное?


person Badgerspot    schedule 12.01.2015    source источник


Ответы (2)


Похоже, я исправил это сейчас.

В моем коде было две ошибки.

Первоначальная ошибка возникла из-за того, что я не знал о проставлении параметра 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";

Как только я добавил владельца, BulkCopy заработал.

Для справки, теперь, когда я заработал, я могу выполнить вызов 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]

Целевая таблица Sybase:

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 для C#, попробуйте Sybase Books Online

Надеюсь, это поможет кому-то.

person Badgerspot    schedule 14.01.2015

У меня нет никаких непосредственных наблюдений, кроме этого: ваша исходная таблица в MS SQL отличается от целевой таблицы в ASE двумя способами:

  1. у него меньше столбцов и

  2. имя столбца в ASE отличается от имен столбцов в MS SQL.

Без понимания всего объема и контекста того, что здесь происходит, было бы нетрудно представить несоответствие между исходной и целевой таблицами.

person RobV    schedule 13.01.2015
comment
Я думал, что это покрывается ColumnMappings. Должны ли исходная и целевая таблицы иметь одинаковые имена и точно такие же имена столбцов, типы и порядок? - person Badgerspot; 13.01.2015
comment
Оказывается, исходная и целевая таблицы не обязательно должны иметь одинаковые имена и точно такие же имена столбцов и порядок. - person Badgerspot; 14.01.2015