Реализации одного из инструментов отладки на примере автоматизации процесса определения внутренней структуры 1С Предприятие 8

Данная статья описывает реализацию одного из инструментов тестирования и отладки. Рассматривается это на примере идентификации внутренней структуры базы данных 1С Предприятие 8.0.(SQL) для произвольной конфигурации.

Данная статья описывает реализацию одного из инструментов тестирования и отладки. Рассматривается это на примере идентификации внутренней структуры базы данных 1С Предприятие 8.0.(SQL) для произвольной конфигурации.

Материал опубликован на сайте Softpoint.ru

Владимир Сердюк

Дано: Произвольная конфигурация на базе 1С Предприятие 8.0. (SQL)

Цель: Максимально автоматизировать процесс идентификации внутренней структуры к объектам на уровне приложения.

Реализация: Для начала необходимо понять, как это можно было бы сделать вручную. Очевидно, брать в руки профайлер настраивать трейсы. Изменяя объекты приложения, сопоставлять данные в трейсах с соответствующими изменениями объектов. В общем, этот процесс не сложный, но довольно-таки трудоемкий и рутинный. На помощь в автоматизации этого процесса нам приходят триггера MSSQL и возможность их динамического создания. Кроме этого, имея возможность определения структуры метаданных как в 1С, так и в MS SQL(системных объектов), мы получаем весь необходимый инструментарий.

Итак, алгоритм автоматизации заключается в выполнении следующих пунктов:

1) Создаем триггера на все объекты MSSQL базы. В реализации триггера указывается запись в отдельную таблицу следующих значений : ИмяТаблицы, ИмяИзмененногоПоля, PK или уникальный индекс измененной записи, ЗначениеИзВременнойТаблицы. В переменную ЗначениеИзВременнойТаблицы будет передаваться из 1С соответствующее изменению в объекте 1С. Собственно говоря, система этих триггеров это есть фактически одна из систем логирования в БД.

2) Реализуем функцию, которая будет передавать в MSSQL значение изменения в объекте 1С. Передавать мы должны таким образом что бы затем можно было получить это значение и присвоить переменной ЗначениеИзВременнойТаблицы в вышеописанной системе триггеров.

3) Организуем циклом перебор метаданных в 1С. Производим последовательное изменение объектов 1С.Передаем в переменную ЗначениеИзВременнойТаблицы конкретное изменение объекта. Передать значение в ЗначениеИзВременнойТаблицы необходимо до выполнения команды изменяющей объект для того что бы триггер получил информацию о том какой объект 1С его вызвал и какие изменения в этом объекте произошли. Собственно говоря, в этом пункте и заключается одна из сложностей не позволяющая этот алгоритм сделать полностью универсальным. Дело в том, что 1С использует агрегацию данных и кроме этого логика изменений зависит от текущего состояния объекта. Если мы изменим, значение одного реквизита в случае, когда документ уже существует в базе и когда этот документ создается впервые в результате получим различный набор команд к SQL серверу. С агрегацией аналогичная ситуация. Предположим у нас есть два одинаковых документа с разницей по дате в год, осуществляющих линейное движение по регистрам(для упрощения без обработки всякой логики). Так вот в случае проведения первого документа мы получим одно количество изменений по агрегационным записям, а случае проведения второго другое количество.

Реализовав подобную систему на выходе, мы получим соответствие объектов 1С к объектам MS SQL. Конечно, нужно понимать, что информация в полученной таблице довольно-таки сыра и потребует некоторой обработки. Кроме этого, можно составить последовательность операций с метаданными и соответствующую обработку результирующей таблицы, чтобы определить автоматически для этой конфигурации внутреннюю структуру данных. Неважно, будем мы заново создавать или удалять эту конфигурацию, в какой последовательности создавать в конфигураторе объекты метаданных - подобная система однозначно определит соответствие. Но важно понимать следующее - для любой произвольно взятой конфигурации эта система работать не будет. Точнее она будет работать, но если для этой конфигурации придумать свою систему изменения объектов на основании метаданных и обработки результирующей таблицы. Но этого по большому счету и не нужно. Подобная система это инструмент. С помощью этого инструмента специалист довольно быстро разберется с любой интересующей его структурой.

Ниже я приведу несложный код для автоматической генерации триггеров на БД.

declare @str char(8000)
declare @Table_name char(100)
declare @id int
declare @Column_name char(100)

declare TableCur cursor local fast_forward for -- Декларация курсора
select [name],[id] from sysobjects
where xtype='U' and status>0 and name<>'Log1CforSQL' 
-- Запрос по всем таблица в текущей БД кроме той куда пишется лог
open TableCur   -- Открытие крсора
fetch TableCur into @Table_name,@id
while (@@fetch_status<>-1)  -- Цикл по курсору
begin 
set @str='if exists (select * from dbo.sysobjects where id = 
object_id(N''[dbo].[TR_U_'+rtrim(@Table_name)+']'') 
and OBJECTPROPERTY(id, N''IsTrigger'') = 1)
drop trigger [dbo].[TR_U_'+rtrim(@Table_name)+']' -- удаляем если он уже существует
exec (@str) 
select @str='CREATE TRIGGER [TR_U_'+rtrim(@Table_name)+'] ON [dbo].['+rtrim(@Table_name)+'] 
		FOR Update
		AS    
		set nocount on
		declare @Izm1CObject char(1000)
		select @Izm1CObject=Izm1CObject from BufferIzm1CObject where spid=@@spid '

declare ColumnCur cursor local fast_forward for 
select [name] from syscolumns  -- Запрос по списку колонок конкретной таблицы
where [id] = @id 
open ColumnCur   -- Открытие курсора
fetch ColumnCur into @Column_name
while (@@fetch_status<>-1)  
begin 
select @str =rtrim(@str)+' if update('+@Column_name+')
    begin	insert into Log1CforSQL(TableName,ColumnName,Izm1CObject,Type)
    values('''+rtrim(@Table_name)+''','''+rtrim(@Column_name)+''',@Izm1CObject,''U'') end'
--Вообще то признак update не гарантирует того что поле изменилось(в 7.7. так и происходило)
--поэтому здесь необходимо сравнивать deleted и inserted , данный вариант - некоторое упрощение
fetch ColumnCur into @Column_name
end
select @str =rtrim(@str)+' set nocount off'
close ColumnCur
deallocate ColumnCur
--Создание триггеров на удаление и вставку. 
--Если текст для создания триггера будет более 8000 символо то этот алгоритм работать не бдет
--Вообще то для этих случаев необходимо создавать текст триггера через временную таблицу например
-- В данном случае так реализованно для простоты понимания
exec (@str)
set @str='if exists (select * from dbo.sysobjects where id = 
object_id(N''[dbo].[TR_D_'+rtrim(@Table_name)+']'') 
and OBJECTPROPERTY(id, N''IsTrigger'') = 1)
drop trigger [dbo].[TR_D_'+rtrim(@Table_name)+']' -- удаляем если он уже существует
exec (@str)
select @str= 'CREATE TRIGGER [TR_D_'+rtrim(@Table_name)+'] ON [dbo].['+rtrim(@Table_name)+'] 
			FOR DELETE
			AS    
			set nocount on
			declare @Izm1CObject char(1000)
			select @Izm1CObject=Izm1CObject from BufferIzm1CObject where spid=@@spid
			insert into Log1CforSQL(TableName,ColumnName,Izm1CObject,Type) 
			values('''+rtrim(@Table_name)+''',''ALL'',@Izm1CObject,''D'')         
			set nocount off'
exec (@str) -- создаем триггер
set @str='if exists (select * from dbo.sysobjects where id = 
object_id(N''[dbo].[TR_I_'+rtrim(@Table_name)+']'') 
and OBJECTPROPERTY(id, N''IsTrigger'') = 1)
drop trigger [dbo].[TR_I_'+rtrim(@Table_name)+']' -- удаляем если он уже существует
exec (@str) 
select @str= 'CREATE TRIGGER [TR_I_'+rtrim(@Table_name)+'] ON [dbo].['+rtrim(@Table_name)+'] 
			FOR INSERT
			AS    
			set nocount on
			declare @Izm1CObject char(1000)
			select @Izm1CObject=Izm1CObject from BufferIzm1CObject where spid=@@spid
			insert into Log1CforSQL(TableName,ColumnName,Izm1CObject,Type) 
			values('''+rtrim(@Table_name)+''',''ALL'',@Izm1CObject,''I'')         
			set nocount off'
exec (@str)-- создаем триггер

fetch TableCur into @Table_name,@id -- Передача названия таблицы из курсора в переменную @Table_name
end
close TableCur
deallocate TableCur

Начать дискуссию