|
10.02.2003, 09:22 | #1 |
Moderator
|
Вставка строк в таблицы Аксапты сторонними средствами
У меня при работе сАксаптой периодически возникает необходимость/желание вставлять данные в таблицы Аксапты какими-либо сторонними средствами. Это может быть как и внешняя программи, так и хранимая процедура на сервере или DTS. Основная проблема при данном подходе – это RecID. Целое число, уникальное в пределей все базы данных, которое генерит Аксапта для каждой вставляемой строки.
Так как по полям DataArea+RecId Аксапта создает уникальный индекс, оставлять это поле незаполненным невозможно. Значит нужно выработать механизм, который позволит внешним программа правильно генерировать это RecId. За генерацию RecID в Аксапте отвечают таблица SystemSequences и класс systemSequence. Про структуру и назначение отдельных столбцов таблицы на форуме уже рассказывали – поэтому не буду повторяться. А вот класс, а точнее его методы рассмотрим: public final int nextVal( [tableId _tableId = 0] ) – возвращает следующий RecID. Это не обязательно тот RecID, который хранится в таблице SystemSequences. Дело в том, что Аксапта выделяет RecId партиями и значение в таблице указывает на первый RecId следющей партии, в то время как метод nextVal() возвращает следующий RecId из кэша(если там еще они есть), либо заставляет Аксапту выделить следующую партиию RecID, поместив их в кэш. public final void setCacheSize(int _NewSize) – этот метод и устанавливает размер партии, которыми выделяется recID. Если вы планируете вставлять очень много записей, может быть имеет смысл установить размер партии побольше, чтобы не блокировать таблицу SystemSequences. public final void flushCache( [tableId _tableId = 0] ) - этот метод засавляет Аксапту очистить кэш, в котором хранятся оставшиеся RecID от последнего выделения. Данные RecId можно считать потерянными для Аксапты. public final int reserveValues(int _nReserved [, tableId _tableId = 0] ) – этот метод засатвляет выделить RecID в количестве _nReserved для Ваших собственных нужд. Метод возвращает значение первого выделенного RecId. При этом Аксапта уже не будет использовать в своих целях ни один из выделенных Вам RecId. public final void suspendRecIds(tableId _tableId) – подавляет генерацию RecID для определенной таблицы. Теперь при вставке записей в эту таблицу RecId не будет геерироваться автоматически, а обязанность заполнения этого поля ложится на программиста. public final void removeRecIdSuspension( [tableId _tableId = 0] ) – восстаналивает автоматический процесс генерации RecID для заданной таблицы. Тепеь вернемся к нашей задаче – заполнении Аксаповских таблиц извне Аксапты или еще точнее генерации RecID для заполняемой таблицы вне Аксапты. Из всех предложенных и рассмотренных мною способов следующий кажется мне наиболее надежным и безопасным: PHP код:
Очевидно, что у данного метода есть два ограничения: Должна быть необходимость передавать параметры во внешнюю программу. Если мы вызываем внешний exe-шник, то этот параметр мы можем передать с помощью метода shellExecute класса WinAPI. Вызов хранимой процедуры тоже позволяет передавать в нее параметры. До вызова внешней программы мы уже должны знать количество вставляемых строк. Иначе, мы просто не будем знать, сколько нам резервировать. Подходы тут могут быть самые разные: или Вы заранее знаете, сколько строк будет вставлено, либо не знаете сколько, но гарантируете, что не больше 100. В этом случае имеет смысл зарезервировать все 100, даже если использованы будут 50. Наконец, это количество может быть вычислено как из Аксапты, так и вызовом той же внешней программы с определенным параметром. И теперь небольшой пример. Допустим, что у меня на SQL Server’е есть хранимая процедура: PHP код:
PHP код:
|
|
|
За это сообщение автора поблагодарили: mazzy (2), raz (5), Alenka (1), Jolly (1), Crusader3000 (1). |
07.05.2009, 16:49 | #2 |
MCITP
|
Предложу свой вариант пакета на PL\SQL реализующий подобные задачи при работе с данными Аксапты извне для Oracle. Написан давно, лет 5 назад, багов вроде не отмечено... Коментариями не "злоупотреблял", вроде в целом всё и так ясно, код несложный. Есть определённые допущения, например хранится только один кэш номеров, для последней компании . Писано для 3.0. Будут вопросы - с удовольствием отвечу.
X++: CREATE OR REPLACE PACKAGE pck_ax_sequence Authid Current_user Is -- RecId Procedure P_set_cache_size ( Parm_cache_size In Pls_integer ); -- Recid Function F_nextval ( Parm_dataareaid In Varchar2 ) Return Number; End; / CREATE OR REPLACE Package Body pck_ax_sequence Is L_cache_next_size Pls_integer := 10; L_cache_curr_size Pls_integer; Type T_cache_table Is Table Of Number Index By Pls_integer; Lt_cache_table T_cache_table; L_index Pls_integer; -- 1 .. L_cache_curr_size L_last_dataareaid Varchar2(5); Procedure P_set_cache_size( Parm_cache_size In Pls_integer) As Begin L_cache_next_size := Parm_cache_size; End; Procedure P_init( Parm_dataareaid In Varchar2) As Pragma Autonomous_transaction; L_new_nextval Number; Begin L_cache_curr_size := L_cache_next_size; Update Systemsequences Set Nextval = Nextval + L_cache_curr_size Where Dataareaid = Parm_dataareaid And Recid = -1 And Name = 'SEQNO' Returning Nextval Into L_new_nextval; L_last_dataareaid := Parm_dataareaid; L_index := 1; For I In 1 .. L_cache_curr_size Loop Lt_cache_table(I) := L_new_nextval - L_cache_curr_size - 1 + I; End Loop; Commit; End; Procedure P_check_nextval( Parm_dataareaid In Varchar2) As Begin If L_last_dataareaid <> Parm_dataareaid Or L_index > L_cache_curr_size Or L_index Is Null Then P_init(Parm_dataareaid); End If; End; Function F_nextval( Parm_dataareaid In Varchar2) Return Number As Begin P_check_nextval(Parm_dataareaid); L_index := L_index + 1; Return Lt_cache_table(L_index - 1); End; End;
__________________
Zhirenkov Vitaly |
|
|
За это сообщение автора поблагодарили: mazzy (2), aidsua (1), Crusader3000 (1). |
Теги |
ax3.0, faq, recid, systemsequences, t-sql, законченный пример, интеграция, номерная серия, нумерация, полезное |
|
|