У меня при работе сАксаптой периодически возникает необходимость/желание вставлять данные в таблицы Аксапты какими-либо сторонними средствами. Это может быть как и внешняя программи, так и хранимая процедура на сервере или 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 код:
первыйRecId = sysSeq.reserveValues(количество всталяемых записей)
Вызов внешней программы/задачи/хранимой процедуры (первыйRecId, [количество всталяемых записей])
То есть, сначала мы резервируем необходимое нам количество RecID, полученомер первого зарезервированного RecID и передаем его в нашу внешнюю программу, подразумевая, что на основе этой информации внешняя программа сама буде генерить RecID.
Очевидно, что у данного метода есть два ограничения:
Должна быть необходимость передавать параметры во внешнюю программу. Если мы вызываем внешний exe-шник, то этот параметр мы можем передать с помощью метода shellExecute класса WinAPI. Вызов хранимой процедуры тоже позволяет передавать в нее параметры.
До вызова внешней программы мы уже должны знать количество вставляемых строк. Иначе, мы просто не будем знать, сколько нам резервировать. Подходы тут могут быть самые разные: или Вы заранее знаете, сколько строк будет вставлено, либо не знаете сколько, но гарантируете, что не больше 100. В этом случае имеет смысл зарезервировать все 100, даже если использованы будут 50. Наконец, это количество может быть вычислено как из Аксапты, так и вызовом той же внешней программы с определенным параметром.
И теперь небольшой пример. Допустим, что у меня на SQL Server’е есть хранимая процедура:
PHP код:
create proc MultipleTable
@beginRecId int
as
set nocount on
declare @i int
set @i = 0
while (@i<>10)
begin
insert into dem_multi values(@i*@i, 'dat', @beginRecId + @i)
set @i = @i + 1
end
А вот пример вызова это хранимой процедуры из Аксапты:
PHP код:
static void Job11(Args _args)
{
dem_Multi multi;
Connection con = new Connection();
Statement stmt = con.createStatement();
systemSequence sysSqnc;
int beginRecId;
;
delete_from multi;
sysSqnc = new systemSequence();
beginRecId = sysSqnc.reserveValues(10);
stmt.executeUpdate("exec [Axapta].[dbo].[MultipleTable] " + int2str(beginRecId));
}