Добрый день!

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

 

Спасибо!

Нравится

4 комментария
Лучший ответ

Каскадная связь при настройке детали по полю контрагент должна помочь

Каскадная связь при настройке детали по полю контрагент должна помочь

Алексей Следь, спасибо большое!))) В 7.17 не могу её найти((( 

"Удалять записи" не помогает.

 

 

Екатерина, непонятно, почему у Вас подписи переключателей такие, а не «Блокировать удаление, если есть связанные записи в текущем объекте с этим значением» и «Удалять записи из текущего объекта с этим значением», как написано при открытии в дизайнере стандартной детали, вроде «Контрагент в группе». Там у поля связи с разделом выбрано второе значение.

На всякий случай, старая конфигурация доступна на /0/dev_old и можно включить каскадную связь там.

Зверев Александр,

Cпасибо большое! Помогло переключение на старую конфигурацию!)

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

Всем привет!
Все мы знаем, что, если при удалении записи на нее есть ссылки из других таблиц, то система выдает список связей для того, чтобы пользователь попробовал разобраться с этим, где нужно удалил эти связи или вообще отказался от затеи удалять ту самую запись. Но, на мой взгляд, в 90% случаев пользователь уверен, что эту запись точно нужно удалить и разбираться со связями он 100% не хочет. Так почему бы не дать ему возможность просто удалить эту запись, предварительно отвязав ее от остальных объектов автоматически?

Для решения этой задачи был взят за основу скрипт отсюда.

1. Создаем хранимую процедуру под sa или под пользователем с правом sysadmin, которая будет делать отвязку записи и ее удаление:

CREATE procedure tsp_UnbindAndDeleteRecord(@RecordID nvarchar(max), @ParentTableName nvarchar(max)) WITH exec AS owner AS
begin
        declare @ColumnName nvarchar(max)
        declare @TableName nvarchar(max)
        declare @TempSQL nvarchar(max)
        declare @RecordValue nvarchar(max)

        declare local_cursor cursor LOCAL FOR
        SELECT DISTINCT
                CONSTRAINT_COLUMN_USAGE.COLUMN_NAME AS COLUMN_NAME,
                CONSTRAINT_COLUMN_USAGE.TABLE_NAME AS TABLE_NAME
        FROM ((INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS CONSTRAINT_COLUMN_USAGE
        INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TABLE_CONSTRAINTS
                ON CONSTRAINT_COLUMN_USAGE.CONSTRAINT_NAME = TABLE_CONSTRAINTS.CONSTRAINT_NAME)
        INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS REFERENTIAL_CONSTRAINTS
                ON CONSTRAINT_COLUMN_USAGE.CONSTRAINT_NAME = REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME)
        INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS PARENT_TABLES
                ON REFERENTIAL_CONSTRAINTS.UNIQUE_CONSTRAINT_NAME = PARENT_TABLES.CONSTRAINT_NAME
        WHERE TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'FOREIGN KEY' AND
                PARENT_TABLES.TABLE_NAME = @ParentTableName

        IF (isnull(cast(@RecordID AS nvarchar(max)), '') = '')
                RETURN

        open local_cursor
        fetch next FROM local_cursor INTO @ColumnName, @TableName

        while @@fetch_Status = 0
        begin
                SET @TempSQL = 'UPDATE [' + @TableName + '] SET [' + @ColumnName + '] = null' + ' WHERE ['+ @ColumnName + '] = ''' + @RecordID + ''''
                exec sp_executesql @TempSQL
                fetch next FROM local_cursor INTO @ColumnName, @TableName
        end
        close local_cursor
        deallocate local_cursor

        SET @TempSQL = 'delete from [' + @ParentTableName + '] WHERE [ID] = ''' + @RecordID + ''''
        exec sp_executesql @TempSQL
end

--grant execute on tsp_UnbindAndDeleteRecord to public

Как вы может быть заметили, процедура создана с "with exec as owner". Добавил это я на всякий случай, если вдруг вы не дадите гранты на использование этой процедуры пользователям.

2. Ищем сервис окна wnd_DeleteRecordsWizard, которое появляется, когда выводится список связанных объектов при удалении записей. Добавляем во фрейм с кнопками свою кнопку btnDeleteForce и даем ей "Заголовок" = "Удалить принудительно".

3. На OnClick этой кнопки "вешаем" наш код, в котором запускаем нашу процедуру из пункта 1, передавая в нее в качестве параметров ID удаляемых записей (у нас их ведь может быть сколько угодно) и имя таблицы, из которой производится удаление.

function btnDeleteForceOnClick(Control) {
        var Dataset = dlData.Dataset;
        if (Dataset.IsEmptyPage) {
                return;
        }
        if (ShowConfirmationDialog("Вы уверены?") != wmrYes) {
                return;
        }
        var TableName = Self.Attributes('TableName');
        if (IsEmptyValue(TableName)) {
                return;
        }
        var RecordIDs = Self.Attributes('RecordIDs');
        if (!RecordIDs) {
                return;
        }
        var Count = RecordIDs.length;
        var RecordID;
        try {
                System.BeginProcessing();
                for (var i = 0; i Count; i++) {
                        System.ProcessMessages();      
                        RecordID = RecordIDs[i];
                        var sql = "exec tsp_UnbindAndDeleteRecord '" +
                                RecordID + "', '" + TableName + "'";
                        Connector.DBEngine.ExecuteCustomSQL(sql, System.EmptyValue);
                }
        } finally {
                System.EndProcessing();
        }
        Self.Close();
}

4. Все-таки позволять всем пользователям принудительно удалять запись - дело рискованное. Поэтому предлагаю позволять это делать ответственному человеку, а именно пользователю с правами администратора системы. Для этого в OnPrepare окна wnd_DeleteRecordsWizard добавляем код показа нашей кнопки:

btnDeleteForce.IsVisible = Connector.CurrentUser.IsAdmin;

5. Сохраняем сервисы и проверяем.

Если же вы, все-таки, решите позволять такое удаление любому пользователю, то, как понимаете, пункт 4 делать не нужно.

Примечание: Проверялся этот функционал на MS SQL 2008 (для Oracle он вообще не подходит, как Вы можете судить по синтаксису хранимой процедуры), но, думаю, он будет работать и на MS SQL 2005.

Нравится

Поделиться

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

Спасибо S.Kalishenko. Полезный функционал. Только я так понял доработка для версии террасофт начиная с 3.3.2 так как в версии 3.3.1 еще нет окна wnd_DeleteRecordsWizard. Я думаю как вариант сделать в окне wnd_BaseGridArea в amDelete еще один пунк "Удалить принудительно" и поправить код следующим образом

var Dataset = dlData.Dataset;
        if (Dataset.IsEmptyPage) {
                return;
        }
        if (ShowConfirmationDialog("Вы уверены?") != wmrYes) {
                return;
        }
        var TableName = GetTableFromDataset(Dataset);
        if (IsEmptyValue(TableName)) {
                return;
        }
        var RecordIDs = GetGridSelectedIDsArray();
        if (!RecordIDs) {
                return;
        }
        var Count = RecordIDs.length;
        var RecordID;
        try {
                System.BeginProcessing();
                for (var i = 0; i < Count; i++) {
                        System.ProcessMessages();      
                        RecordID = RecordIDs[i];
                        var sql = "exec tsp_UnbindAndDeleteRecord '" +
                                RecordID + "', '" + TableName.SQLName + "'";
                        Connector.DBEngine.ExecuteCustomSQL(sql, System.EmptyValue);
                }
        } finally {
                System.EndProcessing();
        }

а и еще вопрос а возможно сделать деталь в которой бы отображалось в каких таблицах данная запись имеет связанные записи?

Клёвая штука! Надо использовать обязательно!

"Мещеринов Иван Александрович" написал:Только я так понял доработка для версии террасофт начиная с 3.3.2 так как в версии 3.3.1 еще нет окна wnd_DeleteRecordsWizard.

Да, в 3.3.1 можно реализовать функционал как Вы описали.

"Мещеринов Иван Александрович" написал:а и еще вопрос а возможно сделать деталь в которой бы отображалось в каких таблицах данная запись имеет связанные записи?

Можно, только код я не готов Вам предоставить. Для такой детали можно воспользоваться реализацией получения датасета в wnd_DeleteRecordsWizard из 3.3.2.

Здравствуйте, сообщество.

Сегодня сделал аналогичный функционал для БД Oracle.

Изменяем метод btnDeleteForceOnClick(Control) до следующего вида:

function btnDeleteForceOnClick(Control) {
	ForceDeleteRecord(dlData.Dataset, 
		Self.Attributes('TableName'), Self.Attributes('RecordIDs'));
	Self.Close();
}

Добавляем метод ForceDeleteRecord(Dataset, TableName, RecordIDs) в тот же модуль:

function ForceDeleteRecord(Dataset, TableName, RecordIDs) {
	if (!Dataset || IsEmptyValue(TableName)) {
		return;
	}
	if (Dataset.IsEmptyPage) {
		return;
	}
	if (ShowConfirmationDialog("Вы уверены?") != wmrYes) {
		return; 
	}
	if (!RecordIDs) {
		return;
	}
	var Count = RecordIDs.length;
	var RecordID; 
	try {
		System.BeginProcessing();
		for (var i = 0; i < Count; i++) {
			System.ProcessMessages();       
			RecordID = RecordIDs[i];
			var sql = '';
			switch (Connector.DBExecutor.DBExecutorTypeCode) {
				case 'MSSQL':
					var sql = "exec tsp_UnbindAndDeleteRecord '" + 
						RecordID + "', '" + TableName + "'";
					break;
				case 'Oracle':
					var sql = "begin \"tsp_UnbindAndDeleteRecord\""('"" + 
Показать все комментарии