Добрый день!
Появилась необходимость синхронизации контрагентов межу двумя базами.
Одна база Terrasoft 3.3 Sales - Вторая ТС 3.2 X15. MS SQL 2005.
Подскажите пожалуйста как лучше реализовать такую синхронизацию.
Заранее спасибо!
Нравится
И все-таки. Нужна именно синхронизация. Или импорт из старой базы в новую ?
Мне кажется, проще всего написать скрипт, который курсором проходится по записям таблицы контрагентов одной базы, проверяет, есть ли контрагент с текущим названием во второй базе, и если нет, добавляет его. Потом аналогично для второй базы. Для того, чтобы каждый раз не проверять все записи, можно создать системный параметр "Последняя дата импорта" и проверять только те записи, дата изменения которых больше значения этого параметра.
Второй вариант - импорт в 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" написал:Решил пока сделать с помощью действия "Добавить контакт во вторую БД".
Решение не очень изящное, но тогда нужно продумать еще действие для изменения. И завязать их на автоматическую работу - чтобы исключить человеческий фактор.
"Serega" написал:т.к. вторая конфигурация 3.3, а первая 3.2. Что делать в таком случае?
Не обратил внимания, что версии разные. Тогда проще будет через 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