Копирование проекта. Проблема с реестрами, встроенными в карточку редактирования

Добрый день!

У меня в карточке проекта встроено несколько реестров.
Как мне при копировании проекта копировать и эти реестры со всеми данными в них?
Я хотела сделать на dlDataOnDatasetAfterCopy сохранение записи и потом вставку данных в реестры, но у меня в этом событии еще не заполнены другие поля проекта.

1) Где мне лучше сохранить проект? OnShow, может быть?
2) Каким образом я потом пойму, что датасет у меня копирован? И как лучше организовать передачу данных из встроенных реестров в новый проект?

Нравится

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

Признак копирования - в создаваемое окно при копировании записи передается атрибут 'SourceRecordID' с соответствующим значением. Плюс если не путаю атрибут 'IsCopy'

С встроенными реестрами сложнее... я бы сделал как вариант так - свой обработчик кнопки Копировать, любым способом создаем копию текущей записи с набором нужных реквизитов, к ней крепим нужные записи из встроенных реестров (как продукты в документах, счетах и так далее). Потом поднимаем карточку уже готовой записи на правку, если необходимо.

У меня небольшая проблема возникла. Думаю, что решение простое, просто я не могу найти его :sad:
Копирование встроенных реестром у меня происходит тут:

function dlDataOnDatasetAfterCopy(Dataset, KeyValue) {    
	var TArray = GetData('ds_UserTypes', KeyValue, 'UserTypeID');//сбор записей из встроенного реестра существующего проекта
	Dataset.Post();
	var ProjectID = Dataset('ID');
	SetData('ds_UserTypesInProject', ProjectID, TArray, 'UserTypeID');//вставка данных в строенный реестр нового проекта
	Dataset.Open();
	Dataset.Edit();
	RefreshDetails();//рефреш детали (в карточке проекта),на которой расположен встроенный реестр	
}

После этого у меня остается открытой карточка нового проекта, но там не отображаются данные в строенном реестре и при попытке добавить запись в реестр появляется ошибка:

---------------------------
Error
---------------------------
Ошибка сохранения записи. Оригинальное сообщение об ошибке: The statement has been terminated.
The INSERT statement conflicted with the FOREIGN KEY constraint "FUserTypesInProjectProjectID". The conflict occurred in database "CRM", table "dbo.tbl_Project", column 'ID'
---------------------------
OK   
---------------------------

Если закрыть карточку нового проекта и открыть заново, тогда все записи на месте и все работает корректно. Мне нужно правильно переоткрыть карточку после записи данных в строенный реестр. Что я не так делаю?

Самое банальное -- попробуйте сделать Post датасета :
Dataset.Post();
после обновления детали.

нет, не помогает. проблема все еще актуальна.

Ошибка происходит из-за наличия внешнего ключа FUserTypesInProjectProjectID в таблице tbl_UserTypes. Видимо запись данных во встроенный реестр (а именно поля ProjectID) происходит до того, как этот ID попадает в таблицу tbl_Project. Соответственно по проверке целостности происходит ошибка.

Нет, я же перед заполнением встроенного реестра делаю Dataset.Post() и только после этого беру получившийся ProjectID и пишу его в датасет встроенного реестра.
У меня проблема именно в отображении карточки проекта, на ней нет возможности добавить записи в встроенный реестр почему-то. Если переоткрываю карточку, там есть записи в реестрах скопированные.
Была попытка закрыть в скрипте окно проекта (Self.Close()) и затем снова открыть его на редактирование , но ошибка все равно была та же.
Я думала, что RefreshDetail, который использую в коде поможет, но ошиблась.
Может кто-то подсказать, как правильно произвести создание копии и открытие на редактирование записи с встроенными реестрами?

Обратитесь, пожалуйста, в службу поддержки, предоставив все сервисы ветки проектов (как я понимаю детали в карточке ссылаются на стандартные разделы, а не доработанные). Нужно видеть Вашу реализацию.

Реестры в карточке - это просто данные из справочников. Справочники доработанные. А деталь в карточке - это просто Page для разделения полей на карте, а то все не умещаются.

"Kat" написал:Нет, я же перед заполнением встроенного реестра делаю Dataset.Post() и только после этого беру получившийся ProjectID и пишу его в датасет встроенного реестра.

Вот здесь и проблема. ID в момент копирования датасета также копируется, новый не генерируется. Потому и проблема с внешним ключом. Нужно ID сгенерировать, потом сделать Post, а потом уже и скопировать все детали. К тому же вызовы Open и Edit после Post'а уже ни к чему. Рекомендую переписать Вашу функцию таким образом:

function dlDataOnDatasetAfterCopy(Dataset, KeyValue) {    
        var TArray = GetData('ds_UserTypes', KeyValue, 'UserTypeID');//сбор записей из встроенного реестра существующего проекта
        var RecordID = Connector.GenGUID();
        Dataset.Values('ID') = RecordID;
        Dataset.Post();
        var ProjectID = RecordID;
        SetData('ds_UserTypesInProject', ProjectID, TArray, 'UserTypeID');//вставка данных в строенный реестр нового проекта
        RefreshDetails();//рефреш детали (в карточке проекта),на которой расположен встроенный реестр    
}

в функции CopyRecord есть генерация ID для новой записи, поэтому после копирования выдается ошибка

function CopyRecord(BaseDBEdit, Window){
	var Dataset = BaseDBEdit.Dataset;
	Dataset.DisableGettingDisplayValues();
	try {
		var SourceRecordID = Window.Attributes('SourceRecordID');
		try {
			Dataset.Copy(SourceRecordID);// тут перескакивает в мой обработчик
		} catch (E){
			ShowWarningDialog(E.message);
			Dataset.Close();
			return;
		}
	    BaseDBEdit.RecordID = Connector.GenGUID();
		Dataset.ValAsGUID('ID') = BaseDBEdit.RecordID;//тут вылетает
		Window.Attributes('RecordID') = BaseDBEdit.RecordID;
		SetDefaultValues(BaseDBEdit);
	} finally {
		Dataset.EnableGettingDisplayValues();
	}
	SetEditWindowCaption(BaseDBEdit, Window);
}

В Ваш обработчик перескакивает еще до генерации нового ID, который уже на тот момент Вам нужен для копирования деталей. Поэтому предлагаю генерацию ID в dlDataOnDatasetAfterCopy оставить, а написать проверку в CopyRecord на то, не был ли еще сгенерирован ID : вместо

Dataset.ValAsGUID('ID') = BaseDBEdit.RecordID;

писать

if (IsEmptyGUID(Dataset.ValAsGUID('ID'))) {
   Dataset.ValAsGUID('ID') = BaseDBEdit.RecordID;
}

Виталий, спасибо за совет!
Немного изменила ваш пример кода на:

if (IsEmptyGUID(Dataset.ValAsGUID('ID'))) {
	BaseDBEdit.RecordID = Connector.GenGUID();
	Dataset.ValAsGUID('ID') = BaseDBEdit.RecordID;
} else {	
	BaseDBEdit.RecordID = Dataset.ValAsGUID('ID');
}

все работает!

Огромное всем спасибо за помощь!!!!

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