31.10.2011, 19:14 | #1 |
Участник
|
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();
} Метод ccADORecordSet.moveNext() добавил в класс ccADORecordSet по аналогии со старыми версиями Axapta. Т.е. там только собственно команда recordSet.moveNext() В чем причина подобного поведения и как исправить? PS: Соединение необходимо устанавливать именно на стороне сервера. Поэтому варианты выполнения на стороне клиента - не годятся.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
31.10.2011, 19:40 | #2 |
Участник
|
А выборка точно формируется на серверной стороне? Не совсем ваш случай, но может чем-то поможет Если select на сервере а next на клиенте...
|
|
31.10.2011, 19:52 | #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 |
NavAx
|
У нас все работает. Сделаны серверные копии классов CCADOCommand, CCADOConnection, CCADOField, CCADOFields, CCADORecordSet. Во всех методах, где есть взаимодествие с COM добавлен new InteropPermission(InteropKind::ComInterop).assert(). Все статические методы сделаны серверными.
|
|
01.11.2011, 17:40 | #5 |
Участник
|
Пока удалось выяснить, что 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(). Все статические методы сделаны серверными.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... Последний раз редактировалось Владимир Максимов; 01.11.2011 в 17:51. |
|
01.11.2011, 18:19 | #6 |
Moderator
|
Сталкивался с похожим поведением recordset'а при выполнении горячо любимого экспорта в Excel с помощью CopyFromRecordset (правда, на локальной машине).
Так вот, при выполнении экспорта кодом X++ нормально выводились все записи. Когда же вывод выполнялся кодом VBA внутри Excel (казалось бы!), то приходилось перед CopyFromRecordset вставлять recordSet.MoveFirst, так как без этой команды после заполнения рекордсета курсор всегда оказывался на последней записи и только ее и выводил. Теперь, не особо вдаваясь в подробности, для гарантии всегда вставляю этот MoveFirst. |
|
|
За это сообщение автора поблагодарили: blokva (1), gl00mie (2). |
01.11.2011, 18:31 | #7 |
Участник
|
Цитата:
Сообщение от Gustav
Сталкивался с похожим поведением recordset'а при выполнении горячо любимого экспорта в Excel с помощью CopyFromRecordset (правда, на локальной машине).
Так вот, при выполнении экспорта кодом X++ нормально выводились все записи. Когда же вывод выполнялся кодом VBA внутри Excel (казалось бы!), то приходилось перед CopyFromRecordset вставлять recordSet.MoveFirst, так как без этой команды после заполнения рекордсета курсор всегда оказывался на последней записи и только ее и выводил. Теперь, не особо вдаваясь в подробности, для гарантии всегда вставляю этот MoveFirst. В данном же случае это не работает ряду причин: 1. Полученный RecordSet имеет CursorType = 0 - adOpenForwardOnly. Т.е. перемещение "назад" в принципе невозможно. Только вперед. 2. То единственное значение, которое все-таки выводится, это значение из первой записи выборки. Т.е. как раз с позиционированием все в порядке! В начале цикла указатель стоит на первой записи. Проблема именно с перемещением на следующую запись. В данном случае возникает неоднозначность в том, относительно чего эту самую следующую запись отсчитывать. "Теряется" понятие текущей записи. PS: Я пробовал делать MoveFirst(). Как и предполагалось - не помогает, хотя и ошибок не возникает. Просто игнорируется...
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Gustav (2). |
02.11.2011, 10:19 | #8 |
NavAx
|
|
|
02.11.2011, 21:08 | #9 |
Участник
|
У нас тоже все работает.
Все классы 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 |
Участник
|
Похоже, что это глюк установленного на сервере драйвера.
Сейчас попробовал с другим драйвером и вообще получил сообщени об ошибке при использовании Move() (полученный тип RecordSet не поддерживает относительную адресацию, что правильно в данном случае), хотя MoveNext() отработал как положено. Проблема в том, что клиент 32-разрядный, а сервер AOS - 64-разрядный. Вот и мучаюсь с оракловыми драйверами
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
03.11.2011, 12:23 | #11 |
Участник
|
Я скачал и установил драйвер 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 |
Участник
|
Не хотите попробовать 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 |
Участник
|
Это чтобы вместо борьбы с одними глюками начать бороться с другими?
Цитата:
Цитата:
Объект "CLRObject" не может быть создан
Да, чтобы не было недоразумений немного поясню. Собственно Axapta работает на MS SQL 2005. А на Oracle 10g работает другое приложение. Вот мне и надо подключиться к базе этого "другого" приложения. Сервер - Windows 2003 x64, клиент WinXP x32
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Pustik (2). |
03.11.2011, 19:23 | #14 |
Участник
|
Цитата:
У нас не работает, периодически(т.е. то работает, то не работает), элементарная выгрузка данных в ексель через .net Ужас.
__________________
-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. |
|
04.11.2011, 21:39 | #15 |
Участник
|
Цитата:
По поводу драйверов - естественно драйвер oracle нужно устанавливать в соответствии с типом ОС клиента или сервера соответственно (32 или 64 бит). На код в Аксапте это никак не влияет - один и тот же код будет без изменений работать вне зависимости от типа используемого драйвера NET (32 или 64 бит). Позвольте не согласится с такой оценкой технологии NET вообще. В Вашем случае скорее причина не в net а в екселе. Из своего опыта скажу что использование NET в Аксапта при доступе к внешним БД достаточно технологично, универсально, надежно. Практически для любой БД имеется драйвер ADO NET для доступа к данным. Скорость работы (производительность) весьма достойна. Технические возможности обширны: - параметризированные запросы - управление транзакциями - обращение к метаданным БД - режим доступа к бд, когда результат запроса (выборки select) кешируется в в объект Net DataTable что дает возможность не держать открытое соединение с БД в момент исполнения кода а работать с копией данных результата запроса... В общем считаю NET оптимальным средством для обращения из Axapta к любым внешним БД. Думаю тут вообще без вариантов... |
|
05.11.2011, 13:07 | #16 |
Участник
|
Цитата:
Я, в свою очередь, всегда выступал, выступаю и буду выступать за развитие, за прогресс, за что-то новое.Так что против ничего не имею
__________________
-Ты в гномиков веришь? -Нет. -А они в тебя верят, смотри, не подведи их. Последний раз редактировалось Pustik; 05.11.2011 в 13:09. |
|
07.11.2011, 18:09 | #17 |
Участник
|
raz, alek_frm
Какое значение для переписанных классов у вас имеет свойство Connection.CursorLocation() Как выяснилось, это свойство также оказывает влияение на данную проблему. Если установить его в значение 3 - adUseClient, вместо используемого по умолчанию 2 - adUseServer, то проблема снимается. Посмотреть это свойство можно так X++: Com connection; connection = CCADOConnection.connection(); info(int2str(Connection.CursorLocation())); При изменении CursorLocation на значение 3 формируемый RecordSet получает значение CursorType = 3 - adOpenStatic вместо значения по умолчанию 0 - adOpenForwardOnly.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
07.11.2011, 18:21 | #18 |
NavAx
|
|
|
07.11.2011, 18:42 | #19 |
Участник
|
А к какой базе подключаетесь (включая версию) и с какого сервера (32bit или 64bit)?
PS: Проверил. Изменение Connection.CursorLocation(3) никак не влияет на работу на стороне клиента или при использовании других серверов (и для Oracle, и для MS SQL работает нормально). Думаю, на этом и остановиться, как самом простом решении.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
16.11.2011, 13:39 | #20 |
Участник
|
значение 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 |
|
Похожие темы | ||||
Тема | Ответов | |||
Отладка на сервере | 6 | |||
update_recordset. Бага или фича? | 7 | |||
Вопрос по update_recordset | 5 | |||
Затраты учет\списание | 9 | |||
Формат даты на сервере и клиенте | 2 |
|