Синхронизация 2-х баз ТС 3.2 и ТС 3.3.

Добрый день!
Появилась необходимость синхронизации контрагентов межу двумя базами.
Одна база Terrasoft 3.3 Sales - Вторая ТС 3.2 X15. MS SQL 2005.
Подскажите пожалуйста как лучше реализовать такую синхронизацию.
Заранее спасибо!

Нравится

14 комментариев

И все-таки. Нужна именно синхронизация. Или импорт из старой базы в новую ?

синхронизация - работать продолжать будут в 2-х базах, чтоб не вводить по 2 раза контрагенты

Мне кажется, проще всего написать скрипт, который курсором проходится по записям таблицы контрагентов одной базы, проверяет, есть ли контрагент с текущим названием во второй базе, и если нет, добавляет его. Потом аналогично для второй базы. Для того, чтобы каждый раз не проверять все записи, можно создать системный параметр "Последняя дата импорта" и проверять только те записи, дата изменения которых больше значения этого параметра.

Второй вариант - импорт в Excel из одной базы и загрузка в другую, а потом наоборот.

Слабые места этих вариантов:

1) В общем случае невозможно будет удалить контрагент, который присутствует в двух базах. Если возникнет необходимость в удалении, нужно будет сначала удалить его из двух баз, а только потом проводить синхронизацию.

2) Поскольку работа будет вестись в двух базах, непонятно, какая из них "главнее". Следовательно, возникают проблемы с обновлением записей (записи контрагентов с одинаковыми названиями могут содержать разную информацию).

3) А еще можно триггер написать.
ps. не следует забывать о связанных таблицах, "Средства связи", "Адреса" и т.д

По-сути, речь идет о репликации в рамках определенного набора таблиц (tbl_Account и все связанные с ней, включая справочники) - как вариант возможно пойти по этому пути, только настраивать репликацию на уровне серверов, не привлекая возможности Terrasoft.
В любом случае решение задачи очень нетривиально и "подводных камней" содержит больше чем пользы от такого решения. Я бы подумал о переводе второй базы на более новую версию, разовой синхронизации данных и внесении правок в конфигурацию для нужд двух разных офисов/групп пользователей - затраты на такую работу будут сравнимы.
Если же задача очень узкая - только определенные несколько полей в контрагентах - можно попробовать спланировать триггеры или хп для синхронизации (имхо проще), запускаемые по событиям из клиента Terrasoft: правка записи, создание новой, удаление (самое нетривиальное именно тут, решение "в лоб" - запретить удалять вообще:smile:)

Спасибо!
Решил пока сделать с помощью действия "Добавить контакт во вторую БД".

function amiAddToAnotherBaseOnExecute(ActionMenuItem, Sender) {
        var AccountName = BaseWorkspace.GridDataset.ValAsGUID('Name');
	.......
 
	var TS = CreateObject("TSDskObjectLibrary.DskConnector"); 
        var LoggedIn = TS.Login("AnotherBase"); 
        var sqAccount = TS.Services.GetNewItemByUSI("sq_Account"); 
        var dsAccount = dsAccount.Open();
	dsAccount.Append();
        dsAccount.Values('Name') = AccountName
	............
        dsAccount.Post();
        dsAccount.Close(); 
}

Пример подключения взял из интеграции с 1С. но ругается что нет объекта на строчку:

var TS = CreateObject("TSDskObjectLibrary.DskConnector"); 

Подскажите пожалуйста как в скрипте террасофта подключаться к конфигурации другой БД.
Заранее спасибо!

"Serega" написал:Подскажите пожалуйста как в скрипте террасофта подключаться к конфигурации другой БД.
Заранее спасибо!

Пример
"Serega" написал:Решил пока сделать с помощью действия "Добавить контакт во вторую БД".

Решение не очень изящное, но тогда нужно продумать еще действие для изменения. И завязать их на автоматическую работу - чтобы исключить человеческий фактор.

"Глова Сергей" написал:Пример

Спасибо! Но в указанном примере не видна моя вторая конфигурация

Configuration = Connector.Configurations.Items(CurrentConfiguration);

т.к. вторая конфигурация 3.3, а первая 3.2. Что делать в таком случае?

"Serega" написал:т.к. вторая конфигурация 3.3, а первая 3.2. Что делать в таком случае?

Не обратил внимания, что версии разные. Тогда проще будет через ADO сервисы сделать.

Но все таки, мой совет - напишите триггер на стороне БД.

"Глова Сергей" написал:Тогда проще будет через ADO сервисы сделать.

Спасибо! Есть где-то примеры?

Я бы подбные вещи решал так:
1. первичная синхранизация - разово перебросили все что надо из одной БД в другую.
2. синхранизация на уровне триггеров, если БД не на одном сервере - линковать их.
3. для каждой синхранизируемой таблици определить триггера на insert, update, delete. Если структуры БД одинаковы то можно написать хранимую процедуру, которая будет отталкиваться от названия таблици и типа (I, U, D). А потом еще и скрипт, который сам создаст все триггера ибо по виду они будут практически одинаковыми .

В результате избавите пользователей от кликов - 1, получите синхранизацию в практически реальном врмене - 2.
По-хорошему еще б куда ошибки логировать ...

"Глова Сергей" написал:Но все таки, мой совет - напишите триггер на стороне БД.

Пытаюсь написать тригер на обновление:

USE [base1]
GO
 
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
 
ALTER TRIGGER [dbo].[tr_AddToAnotherBaseUpdate] ON [dbo].[tbl_Account]
FOR UPDATE
AS 
DECLARE @Name    VARCHAR(50), 
        @OffName VARCHAR(50)
DECLARE CUR1 CURSOR FOR
    SELECT 
     [Name]
    ,[OfficialAccountName]
    FROM inserted
OPEN CUR1
FETCH NEXT FROM CUR1 INTO @Name, @OffName
WHILE @@FETCH_STATUS=0
 
BEGIN
if not exists (select * from [base2].[dbo].[tbl_Account] where [Name] = @Name )
     INSERT INTO [base2].[dbo].[tbl_Account] ([ID], [Name], [OfficialAccountName])
     VALUES(newid(), @Name, @OffName)
else 
    UPDATE [base2].[dbo].[tbl_Account]
    SET    [OfficialAccountName] = @OffName 
    where  [Name] = @Name
 
END
 
CLOSE CUR1
DEALLOCATE CUR1

Но при таком тригере карточка контрагента просто зависает (((

а курсор зачем? вы ж одну запись меняете
+ насчет

IF NOT EXISTS (SELECT * FROM [base2].[dbo].[tbl_Account] WHERE [Name] = @Name )

это не хорошо, название могли с лишним пробелом/с буковками разными заглавными/строчными написать...
имхо - по ИНН или чему подобному лучше сравнивать
при репликации для таких целей ID используют не зря

"Serega" написал:Но при таком тригере карточка контрагента просто зависает

Курсоры лучше не трогайте, когда их можно не трогать, они крайне ресурсоемки.
Да и не нужны они в вашем случае.
Зачем на апдейт проверять существование контрагента?
Идея в том, что бы вначале одним запросом или импортом или еще чем актуализировать данные на обоих БД.
А потом ваш триггер на апдейт будет выгдеть как-то так:

UPDATE [base2].[dbo].[tbl_Account] 
SET [base2].[dbo].[tbl_Account].[OfficialAccountName] = u.[OfficialAccountName],
SET [base2].[dbo].[tbl_Account].[Name] = u.[Name]
FROM inserted u
where u.[ID] = [base2].[dbo].[tbl_Account].[ID]

Соотвественно на insert можно пользховаться конструкцией insert select * from inserted.

ЗЫ. может чего напутал с синтаксисом, так что проверяйте в гугле )

ЗЫЗЫ. зацикливается у вас потому что вы сам курсор в цикле не переводите...
надо в тело цикла добавить FETCH NEXT FROM CUR1 INTO @Name, @OffName

Показать все комментарии