AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 31.10.2011, 19:14   #1  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
RecordSet.moveNext() на сервере переходит в конец выборки
Ax2009. По необходимости переписал все классы CCADO...() на работу на стороне сервера, добавив везде

X++:
new InteropPermission(InteropKind::ComInterop).assert();
Однако теперь вполне стандартный код вроде

X++:
ccADORecordSet = ccADOCommand.execute();
while (!ccADORecordSet.EOF())
{
      info(any2str(ccADORecordSet.fields().itemIdx(0).value()));
      ccADORecordSet.moveNext();
}
сканирует только одну (первую) запись выборки. Первая же команда moveNext() переводит RecordSet в состояние EOF() и цикл завершается. В выборке больше одной записи. Это показывает RecordCount()

Метод ccADORecordSet.moveNext() добавил в класс ccADORecordSet по аналогии со старыми версиями Axapta. Т.е. там только собственно команда recordSet.moveNext()

В чем причина подобного поведения и как исправить?

PS: Соединение необходимо устанавливать именно на стороне сервера. Поэтому варианты выполнения на стороне клиента - не годятся.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 31.10.2011, 19:40   #2  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
А выборка точно формируется на серверной стороне? Не совсем ваш случай, но может чем-то поможет Если select на сервере а next на клиенте...
Старый 31.10.2011, 19:52   #3  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Все переделанные классы CCADO имеют значение RunOn = Server. Класс, в котором выполняется обработка также имеет значение RunOn = Server. Вызов класса-обработчика выполняется через статические методы с модификатором server.

Так что, уж и не знаю, где еще "server" поставить

PS: На всякий случай проверил, что возвращает RecordSet.CursorLocation(). Он возвращает 2. По документации это

2 = adUseServer - Default, use the cursor supplied by provider or database

Поскольку AOS выступает в роли клиента, то сервер получается - это другой компьютер (база данных находится не там, где AOS). Возможно, действительно в этом причина. Правда, пока не понятно, как это исправить, ведь CursorLocation надо задать до собственно открытия RecordSet.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...

Последний раз редактировалось Владимир Максимов; 31.10.2011 в 21:00.
Старый 31.10.2011, 23:13   #4  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
У нас все работает. Сделаны серверные копии классов CCADOCommand, CCADOConnection, CCADOField, CCADOFields, CCADORecordSet. Во всех методах, где есть взаимодествие с COM добавлен new InteropPermission(InteropKind::ComInterop).assert(). Все статические методы сделаны серверными.
Старый 01.11.2011, 17:40   #5  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Пока удалось выяснить, что MoveNext() не корректно интерпретирует "точку отсчета". Предположительно, он начинает отсчет с последней записи.

Однако если заменить MoveNext() на просто Move() с явным указанием отсчитывать строки от начала курсора, то все проходит корректно. Т.е. код получается примерно такой

X++:
#define.adBookmarkCurrent(0)  // от текущей записи (вот это умолчание не работает)
#define.adBookmarkFirst(1)   // от первой записи
#define.adBookmarkLast(2)   // от последней записи

ccADORecordSet = ccADOCommand.execute();
while (!ccADORecordSet.EOF())
{

      info(any2str(ccADORecordSet.fields().itemIdx(0).value()));
      i++;
      ccADORecordSet.move(i, #adBookmarkFirst);
}
Ну, счетчик записей можно включить непосредственно в класс, так что, можно считать, проблема решена.

Правда, не понимаю причину данной проблемы. Ощущение такое, что вместо MoveNext() выполняется Move(1, 2). Ну, или "текущая" запись интерпретируется как "последняя" запись.

PS: Кстати, замечу, что при выполнении на стороне клиента ситуация получается обратная. Приведенный код приводит к тому, что цикл выполняется только один раз. Т.е. на стороне клиента надо снова использовать MoveNext().

Цитата:
Сообщение от raz
У нас все работает. Сделаны серверные копии классов CCADOCommand, CCADOConnection, CCADOField, CCADOFields, CCADORecordSet. Во всех методах, где есть взаимодествие с COM добавлен new InteropPermission(InteropKind::ComInterop).assert(). Все статические методы сделаны серверными.
А как у Вас реализован метод RecordSet.MoveNext() в переписанных классах? В оригинальных классах ведь его нет.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...

Последний раз редактировалось Владимир Максимов; 01.11.2011 в 17:51.
Старый 01.11.2011, 18:19   #6  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Сталкивался с похожим поведением recordset'а при выполнении горячо любимого экспорта в Excel с помощью CopyFromRecordset (правда, на локальной машине).

Так вот, при выполнении экспорта кодом X++ нормально выводились все записи. Когда же вывод выполнялся кодом VBA внутри Excel (казалось бы!), то приходилось перед CopyFromRecordset вставлять recordSet.MoveFirst, так как без этой команды после заполнения рекордсета курсор всегда оказывался на последней записи и только ее и выводил.

Теперь, не особо вдаваясь в подробности, для гарантии всегда вставляю этот MoveFirst.
За это сообщение автора поблагодарили: blokva (1), gl00mie (2).
Старый 01.11.2011, 18:31   #7  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от Gustav Посмотреть сообщение
Сталкивался с похожим поведением recordset'а при выполнении горячо любимого экспорта в Excel с помощью CopyFromRecordset (правда, на локальной машине).

Так вот, при выполнении экспорта кодом X++ нормально выводились все записи. Когда же вывод выполнялся кодом VBA внутри Excel (казалось бы!), то приходилось перед CopyFromRecordset вставлять recordSet.MoveFirst, так как без этой команды после заполнения рекордсета курсор всегда оказывался на последней записи и только ее и выводил.

Теперь, не особо вдаваясь в подробности, для гарантии всегда вставляю этот MoveFirst.
Ну, я здесь не вижу противоречия. Точнее, надо уточнить как внутри себе Excel передает RecordSet в метод CopyFromRecordset(). Вполне возможно, что действительно запоминает текущее положение указателя. Ну, а раз текущей является последняя запись, то последнюю и выводит.

В данном же случае это не работает ряду причин:

1. Полученный RecordSet имеет CursorType = 0 - adOpenForwardOnly. Т.е. перемещение "назад" в принципе невозможно. Только вперед.

2. То единственное значение, которое все-таки выводится, это значение из первой записи выборки. Т.е. как раз с позиционированием все в порядке! В начале цикла указатель стоит на первой записи.

Проблема именно с перемещением на следующую запись. В данном случае возникает неоднозначность в том, относительно чего эту самую следующую запись отсчитывать. "Теряется" понятие текущей записи.

PS: Я пробовал делать MoveFirst(). Как и предполагалось - не помогает, хотя и ошибок не возникает. Просто игнорируется...
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: Gustav (2).
Старый 02.11.2011, 10:19   #8  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
А как у Вас реализован метод RecordSet.MoveNext() в переписанных классах? В оригинальных классах ведь его нет.
Взято с DAX3 и дабален assert.
X++:
void moveNext()
{
    new InteropPermission(Interopkind::ComInterop).assert();
    recordSet.moveNext();
}
Старый 02.11.2011, 21:08   #9  
alek_frm is offline
alek_frm
Участник
 
5 / 10 (1) +
Регистрация: 31.05.2006
У нас тоже все работает.
Все классы CCADO имеют значение RunOn = Called from,
класса-обработчикa имеют значение RunOn = Server
Command in AOS configuration file : caslevel,Text,disable
X++:
[COLOR=#000000]void moveNext()
{
    recordSet.moveNext();
}[/COLOR]
[COLOR=#000000][/COLOR]

constr="Provider=SQLNCLI10;Persist Security Info=true;Data Source=xxx.xxx.xxx.xxx;Initial Catalog=PROD;User Id=sa;Password=xxx";
Старый 03.11.2011, 12:04   #10  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Похоже, что это глюк установленного на сервере драйвера.

Сейчас попробовал с другим драйвером и вообще получил сообщени об ошибке при использовании Move() (полученный тип RecordSet не поддерживает относительную адресацию, что правильно в данном случае), хотя MoveNext() отработал как положено.

Проблема в том, что клиент 32-разрядный, а сервер AOS - 64-разрядный. Вот и мучаюсь с оракловыми драйверами
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 03.11.2011, 12:23   #11  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Я скачал и установил драйвер Oracle "64-bit Oracle 10g Release 2 ODAC 10.2.0.3 for Windows x64" вот с этой страницы

64-bit Oracle Data Access Components (ODAC) Downloads

Именно с этим драйвером и возникла проблема. Может, есть какие-то особенности настройки драйвера Oracle для версии 10g?
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 03.11.2011, 13:17   #12  
someOne is offline
someOne
Участник
Аватар для someOne
 
174 / 432 (15) +++++++
Регистрация: 11.12.2008
Адрес: Москва
Не хотите попробовать NET ? Нет проблем с запуском на стороне сервера, других глюков вроде бы тоже не замечено...

Например как то так:
X++:
static void transferFromOraWindowsUserLogin(Args _args)
{
    str  connectionstring;
    System.Data.OracleClient.OracleConnection oraDb;
    System.Data.OracleClient.OracleCommand cmd;
    System.Data.OracleClient.OracleDataReader orard;
    EmplTable   emplTable;
    emplId      emplId;
    str         user;

    ;
    connectionstring  = "Data Source = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521)))(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = axapta.domain.ru)));";
    connectionstring += "User Id = admin; Password = topsecret;";

    oraDb = new System.Data.OracleClient.OracleConnection(connectionstring);
    oraDb.Open();


    cmd = new System.Data.OracleClient.OracleCommand("select * from axapta.empltable", oraDb);
    cmd.set_CommandTimeout(6000);


    orard = cmd.ExecuteReader();

    while(orard.Read())
    {
        emplId = orard.GetString(0);
        user = orard.GetString(1);

    }

    info("done");

    orard.Close();
    oraDb.Close();
}
Старый 03.11.2011, 18:56   #13  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от someOne Посмотреть сообщение
Не хотите попробовать NET ?
Это чтобы вместо борьбы с одними глюками начать бороться с другими?

Цитата:
Сообщение от someOne Посмотреть сообщение
Нет проблем с запуском на стороне сервера, других глюков вроде бы тоже не замечено...

Например как то так:
Ну, у кого как Я например, получил сообщение

Цитата:
Объект "CLRObject" не может быть создан
При попытке создать соединение на стороне сервера. Вот и думай, чего и где надо указать, настроить, установить Я без понятия какие драйвера Oracle надо устанавливать для соединения по Net и надо ли устанавливать хоть что-то. Впрочем, на клиенте это работает, но клиент 32-разрядный.

Да, чтобы не было недоразумений немного поясню. Собственно Axapta работает на MS SQL 2005. А на Oracle 10g работает другое приложение. Вот мне и надо подключиться к базе этого "другого" приложения.

Сервер - Windows 2003 x64, клиент WinXP x32
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: Pustik (2).
Старый 03.11.2011, 19:23   #14  
Pustik is offline
Pustik
Участник
 
807 / 372 (14) ++++++
Регистрация: 04.06.2004
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Вот и думай, чего и где надо указать, настроить, установить Я без понятия какие драйвера Oracle надо устанавливать для соединения по Net и надо ли устанавливать хоть что-то. Впрочем, на клиенте это работает, но клиент 32-разрядный.
Полностью согласен. Net больше просит настроек, каких-то своих заточек. Кто это знает? только Microsoft. Сидеть и гадать, тоже никакого удовольствия нет. Читать документацию в 3-4 Тома????
У нас не работает, периодически(т.е. то работает, то не работает), элементарная выгрузка данных в ексель через .net
Ужас.
__________________
-Ты в гномиков веришь?
-Нет.
-А они в тебя верят, смотри, не подведи их.
Старый 04.11.2011, 21:39   #15  
someOne is offline
someOne
Участник
Аватар для someOne
 
174 / 432 (15) +++++++
Регистрация: 11.12.2008
Адрес: Москва
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Ну, у кого как Я например, получил сообщение Объект "CLRObject" не может быть создан
Такое сообщение может быть в случае когда на клиенте или сервере (зависит от того где именно исполняется код) не установлены ADO.NET драйвера для Oracle. Эти драйвера устанавливаются при установке клиентской части Oracle (У меня они установились при установке клиентской части Oracle при типе инсталляции "Администратор"). Также нужно иметь ввиду что после добавление в Reference Axapta ссылки на сборку NET Oracle код сможет исполнятся на сервере только после перезапуска АОС!!! До этого будете получать именно такую ошибку...

По поводу драйверов - естественно драйвер oracle нужно устанавливать в соответствии с типом ОС клиента или сервера соответственно (32 или 64 бит). На код в Аксапте это никак не влияет - один и тот же код будет без изменений работать вне зависимости от типа используемого драйвера NET (32 или 64 бит).

Цитата:
Сообщение от Pustik Посмотреть сообщение
элементарная выгрузка данных в ексель через .net
Ужас.
Позвольте не согласится с такой оценкой технологии NET вообще. В Вашем случае скорее причина не в net а в екселе.

Из своего опыта скажу что использование NET в Аксапта при доступе к внешним БД достаточно технологично, универсально, надежно.
Практически для любой БД имеется драйвер ADO NET для доступа к данным. Скорость работы (производительность) весьма достойна. Технические возможности обширны:
- параметризированные запросы
- управление транзакциями
- обращение к метаданным БД
- режим доступа к бд, когда результат запроса (выборки select) кешируется в в объект Net DataTable что дает возможность не держать открытое соединение с БД в момент исполнения кода а работать с копией данных результата запроса...

В общем считаю NET оптимальным средством для обращения из Axapta к любым внешним БД. Думаю тут вообще без вариантов...
Старый 05.11.2011, 13:07   #16  
Pustik is offline
Pustik
Участник
 
807 / 372 (14) ++++++
Регистрация: 04.06.2004
Цитата:
Сообщение от someOne Посмотреть сообщение
Позвольте не согласится с такой оценкой технологии NET вообще. В Вашем случае скорее причина не в net а в екселе.
Может быть оно и так. Но поверьте, с этой проблемой у нас борются программисты далеко не самого низкого уровня уже несколько месяцев.Я в детали и подробности не вдавался, но мнение моих коллег звучит именно так.И не доверять их мнению у меня причин нет.
Я, в свою очередь, всегда выступал, выступаю и буду выступать за развитие, за прогресс, за что-то новое.Так что против ничего не имею
__________________
-Ты в гномиков веришь?
-Нет.
-А они в тебя верят, смотри, не подведи их.

Последний раз редактировалось Pustik; 05.11.2011 в 13:09.
Старый 07.11.2011, 18:09   #17  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
raz, alek_frm

Какое значение для переписанных классов у вас имеет свойство

Connection.CursorLocation()

Как выяснилось, это свойство также оказывает влияение на данную проблему. Если установить его в значение 3 - adUseClient, вместо используемого по умолчанию 2 - adUseServer, то проблема снимается.

Посмотреть это свойство можно так

X++:
Com connection;

connection = CCADOConnection.connection();
info(int2str(Connection.CursorLocation()));
Использовать существующий метод CCADORecordSet.cursorLocation() нельзя, поскольку он устанавливает, а не считывает значение.

При изменении CursorLocation на значение 3 формируемый RecordSet получает значение CursorType = 3 - adOpenStatic вместо значения по умолчанию 0 - adOpenForwardOnly.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 07.11.2011, 18:21   #18  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
raz, alek_frm

Какое значение для переписанных классов у вас имеет свойство

Connection.CursorLocation()
2
Старый 07.11.2011, 18:42   #19  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
А к какой базе подключаетесь (включая версию) и с какого сервера (32bit или 64bit)?

PS: Проверил. Изменение Connection.CursorLocation(3) никак не влияет на работу на стороне клиента или при использовании других серверов (и для Oracle, и для MS SQL работает нормально). Думаю, на этом и остановиться, как самом простом решении.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 16.11.2011, 13:39   #20  
alek_frm is offline
alek_frm
Участник
 
5 / 10 (1) +
Регистрация: 31.05.2006
значение Connection.CursorLocation() = 2

AOS - 5.0.1500.4570 64 bit (Windows 2008 R2 64 bit on Hyper-V)
SQL - 10.50.1753 2008 R2 64 bit (Windows 2008 R2 64 bit on Hyper-V)

X++:
boolean  test()
{
    Com             connection2 ;
    CCADOConnection connection = new CCADOConnection();
    CCADORecordSet  rSet;
    CCADOCommand    commandRs = new CCADOCommand();
    str             sqlString;
    Voucher         _voucher;
    boolean         ret=false;
    
;
    try
    {
        connection.open(constr);
        connection2 = connection.connection();
        info(int2str(Connection2.CursorLocation()));// = 2
        rSet = new CCADORecordSet();
        sqlString = "SELECT TOP 10 LedgerVoucher FROM CUSTINVOICEJOUR";
        commandRs.activeConnection(connection);
        commandRs.commandText(sqlString);
        rSet=commandRs.execute();
        While (!RSet.EOF())
        {
            _voucher=rSet.fields().itemName("LedgerVoucher").value();
            info(_voucher);
 
            rSet.moveNext();
        }
        rSet.close();
        connection.close();
        connection=null;
        ret=true;
    }
    catch (Exception::Deadlock)
    {
        retry;
    }
    catch (Exception::Error)
    {
        connection.close();
        connection=null;
        ret=false;
    }
    return ret;
}
Теги
ado, ax2009, movenext, recordset

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Отладка на сервере Bega DAX: Программирование 6 21.02.2011 15:38
update_recordset. Бага или фича? Lucky13 DAX: Программирование 7 08.04.2009 17:33
Вопрос по update_recordset cherv DAX: Программирование 5 14.07.2006 14:28
Затраты учет\списание AlexeyBP DAX: Функционал 9 12.12.2005 18:19
Формат даты на сервере и клиенте bio_unit DAX: Администрирование 2 25.08.2004 16:44

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 00:54.