29.06.2007, 17:32 | #1 |
Участник
|
Курсор перешел к следующей записи на клиенте, на сервере этого сделать уже нельзя
Добрый день!
При попытке разноски авансового отчета выскакивает ошибка: "Невозможно выбрать запись в Временные операции по налогам (рабочая таблица) (TmpTaxWorkTrans). Курсор перешел к следующей записи на клиенте, на сервере этого сделать уже нельзя." Не могу понять из за чего она может проявиться. Кто нибудь сталкивался с таким сообщением? Из за чего происходит такая ошибка |
|
02.07.2007, 08:57 | #2 |
Злыдни
|
(пусть поправят меня местные гуру программирования)
Временная таблица заполняется на клиенте. Если класс обработки имеет модификатор server, то обращаться к клиентским данным он не сможет. На двухуровневой конфигурации такую ошибку вы не получите, а вот на трехуровневой очень легко наступить на грабли
__________________
люди...считают, что если техника не ломается, то ее не нужно ремонтировать. Инженеры считают, что если она не ломается, то нуждается в совершенствовании. |
|
02.07.2007, 11:56 | #3 |
Участник
|
Цитата:
Заполняться временная таблица может и на клиенте, и на сервере. Заполненная на сервере таблица не передается автоматически на клиента (нужны шаманские действия в коде). Заполненная на клиенте таблица не передается автоматически на сервер (нужны шаманские действия в коде). |
|
02.07.2007, 12:09 | #4 |
Участник
|
Не совсем так.
Обрабатывать временную таблицу, заполненную на клиенте, на сервере можно (мда, коряво звучит). Сергей, обрати внимание, речь идет не о передаче таблицы (т.е. самих данных) на серверную сторону, а о передаче табличной переменной, которая вполне может быть обработана на сервере (т.е. можно вызвать селект и получить данные на вызывающей стороне). Я ничего не говорю о трафике при этом А ошибка такая возникает при "вложенном" селекте по временной таблице. Таблица может заполняться как на клиенте, так и на сервере. Затем, на стороне, где она заполнялась, идет селект. Далее, табличная переменная передается в метод на другую сторону, где по этой же переменной делается выборка. При возврате из метода при попытке вызова next или при следущем шаге итерации и возникает ошибка. Вот небольшой пример, приводящий к ошибке X++: InventTable it; ; it.SetTmp(); ... // it каким-либо образом заполняем на клиенте while select from it //на втором шаге итерации возникнет ошибка { info(it.itemId); classX::staticServerMethod(it); } X++: static server void classX::staticServerMethod(InventTable _it) { ; while select _it { info(_it.itemId); } }
__________________
Axapta v.3.0 sp5 kr2 |
|
02.07.2007, 13:25 | #5 |
Злыдни
|
Цитата:
Сообщение от mazzy
Временная таблица "живет" там, где была добавлена первая запись.
Заполняться временная таблица может и на клиенте, и на сервере. Заполненная на сервере таблица не передается автоматически на клиента (нужны шаманские действия в коде). Заполненная на клиенте таблица не передается автоматически на сервер (нужны шаманские действия в коде).
__________________
люди...считают, что если техника не ломается, то ее не нужно ремонтировать. Инженеры считают, что если она не ломается, то нуждается в совершенствовании. |
|
30.10.2012, 07:38 | #6 |
Участник
|
Подниму тему
Как все-таки бороться с такой ошибкой? У меня она возникает при программном создании заказа в SalesAutoCreate.create(). Таблица с предварительными данными для будущего заказа уже заполнена. |
|
30.10.2012, 07:59 | #7 |
Участник
|
|
|
30.10.2012, 08:12 | #8 |
Участник
|
Ошибка выглядит так:
Невозможно выбрать запись в 'Строки заказов из Cache ИСТУ' ('FromCacheSalesLine') Курсор перешел к следующей записи на клиенте, и на сервере сделать этого уже нельзя. (S) \Classes\SalesAutoCreate_ISTU\nextRecord - line 3 (S) \Classes\SalesAutoCreate_ISTU\create - line 22 (C) \Jobs\Job152 - line 9 На самом деле я в самом начале создания создания заказаю Создала таблицу с данными и класс SalesAutoCreate_ISTU, унаследованный от SalesAutoCreate. Выполнение инициирую с job вот так: SalesAutoCreate = SalesAutoCreate::construct(fromCacheSalesLine); SalesAutoCreate.create(); Все методы классов для одной записи выполняются корректно, но переход на следующую запись не выполняется. |
|
30.10.2012, 08:59 | #9 |
Участник
|
А вы в джобе случайно записи таблицы fromCacheSalesLine не перебираете? Можете привести код джоба?
|
|
30.10.2012, 09:12 | #10 |
Участник
|
вот job:
FromCacheSalesLine fromCacheSalesLine; SalesAutoCreate SalesAutoCreate = new SalesAutoCreate(); select forupdate fromCacheSalesLine; SalesAutoCreate = SalesAutoCreate::construct(fromCacheSalesLine); SalesAutoCreate.create(); |
|
30.10.2012, 09:52 | #11 |
Участник
|
Перенесите строчку
X++: select forupdate fromCacheSalesLine; |
|
30.10.2012, 09:52 | #12 |
Участник
|
Для чистоты эксперимента сделала все так, как указано в примере http://microsoft-dynamics-ax-erp.blo...ders-with.html
Здесь обрабатывается подобная ошибка, но у меня нет макроса #OCCRetryCount, который используется в последнем методе, нет значения Exception::UpdateConflict Видимо наша система более старой версии. Подскажите, как можно эту обработки подредактировать. |
|
30.10.2012, 09:56 | #13 |
Участник
|
Цитата:
Сообщение от Fizik
Для чистоты эксперимента сделала все так, как указано в примере http://microsoft-dynamics-ax-erp.blo...ders-with.html
Цитата:
the final step is to call the logic from a job or a RunBaseBatch class, make sure that you select records on the same tier as the nextRecord will run or else it will fail. Preferably on the server tier.
Последний раз редактировалось S.Kuskov; 30.10.2012 в 09:58. |
|
30.10.2012, 10:06 | #14 |
Участник
|
|
|
30.10.2012, 10:17 | #15 |
Участник
|
Цитата:
Воспользуйтесь советом из поста #11 и перенесите select в new(). Тогда будет не важно откуда запускать класс, ведь и команда select и команда next будут на одной и той же стороне. Последний раз редактировалось S.Kuskov; 30.10.2012 в 10:28. |
|
01.11.2012, 04:33 | #16 |
Участник
|
Я перенесла строку, как вы посоветовали. Тогда в методе SalesAutoCreate.create() метод не находит ни одной записи в таблице данных (строка while (this.recordExist()) ).
Цикл не выполняется, процедура заканчивается |
|
01.11.2012, 04:58 | #17 |
NavAx
|
Цитата:
У вас, в начале, объект создается через new, а потом через construct. Надо оставить что-то одно. fromCacheSalesLine это и есть та самая временная таблица? Тогда надо ее чем-то наполнить, наверное? А то у меня складывается впечатление, что в качестве параметра в SalesAutoCreate::construct идет пустая табличная переменная.
__________________
Isn't it nice when things just work? |
|
01.11.2012, 05:08 | #18 |
Участник
|
код с удовольствием приведу в порядок.
Таблица fromCacheSalesLine не совсем временная, но она содержит промежуточные данные. Я лично добавила туда 2 строки. И до переноса select forupdate fromCacheSalesLine; в метод new() первая строка обрабатывалась. Ошибка возникала при переходе ко второй строке. Спасибо на указание первой ошибки. job поправила: FromCacheSalesLine fromCacheSalesLine; SalesAutoCreate SalesAutoCreate; ; SalesAutoCreate = SalesAutoCreate::construct(fromCacheSalesLine); SalesAutoCreate.create(); |
|
01.11.2012, 05:18 | #19 |
NavAx
|
Т.е. это физичкская таблица в 2 строки, которую вы хотите перебирать внутри SalesAutoCreate.create(); ?
а зачем тогда в job-е переменная fromCacheSalesLine объявляется? Наверное эту строчку тоже можно убрать. Равно как и параметр из construct. Ну и, по мере вырождения job-а, становится все более очевидным следующий вопрос: "Что происходит в construct, new и create?"
__________________
Isn't it nice when things just work? |
|
01.11.2012, 06:19 | #20 |
Участник
|
Все происходит ровно так, как в примере http://microsoft-dynamics-ax-erp.blo...ders-with.html , только имя класса и таблицы другое.
Да, перебирать собираюсь именно эти 2 строки. Вот методы: SalesAutoCreate.construct такой: static SalesAutoCreate construct(Common buffer = null, Object object = null) { switch (buffer.tableId) { case tablenum(tmpsalesline) : return new SalesAutoCreate_TmpsalesLine(buffer,object); case tablenum(PurchLine) : return new SalesAutoCreate_ProjPurchLine(buffer,object); case tablenum(TmpSalesItemReq) : return new SalesAutoCreate_TmpSalesItemReq(buffer,object); case tablenum(SalesBasketLine) : return new SalesAutoCreate_Basket(buffer,object); case tablenum(TmpFrmVirtual) : return SalesAutoCreate_Purch::construct(buffer,object); //BUOV 30.10.12 ZNO002 ---> case tablenum(FromCacheSalesLine) : return new SalesAutoCreate_ISTU(buffer,object); //BUOV 30.10.12 ZNO002 ---> default : throw error(strFmt("@SYS23419",tableId2Name(buffer.tableId))); } } SalesAutoCreate_ISTU.new : void new(Common _initFromBuffer, Object _callBackClass) { ; select forupdate fromCacheSalesLine where fromCacheSalesLine.RecId == _initFromBuffer.recId; super(_initFromBuffer,_callBackClass); FromCacheSalesLine = _initFromBuffer; } SalesAutoCreate.create() стандартный: void create() { ; try { setPrefix("@SYS55110"); ttsbegin; while (this.recordExist()) { this.setCust(); setPrefix(#PreFixField(CustTable,AccountNum)); this.setSalesTable(); this.setSalesLine(); setPrefix(#PreFixField(SalesLine,ItemId)); this.nextRecord(); } this.endUpdate(); ttscommit; } catch (Exception:eadlock) { retry; } } |
|