Предотвратить сиквелиз от мягкого удаления строк, на которые есть ссылки где-то еще

Я использую Sequelize.js с установленным для paranoid режимом true.

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

Я нашел два похожих вопроса по этому поводу:

  1. Проверьте, ссылается ли объект на предотвращение мягкого -удаление без изменения базы данных

  2. Sequelize - Предотвратить уничтожение строки при использовании в другом месте в ассоциации < /а>

У 1-го решения не было, но было ограничение, которого у меня нет: прикосновение к БД.

2-й имеет следующее решение:

User.hasMany(Roles, { foreignKey: "whatever", onDelete: 'restrict', onUpdate: 'restrict'}); 

Это определенно решение, но оно потребует много работы, потому что мне нужно иметь такое поведение для всех моих таблиц, и на многие из них ссылаются N других таблиц.

Есть ли способ заставить сиквел всегда проверять ссылки перед обратимым удалением? У меня нет никаких ограничений на прикосновение к БД или выполнение ресурсоемких запросов на хуке beforeBulkDelete.


person Vítor Cardoso Bertolucci    schedule 04.02.2020    source источник


Ответы (1)


Поэтому я придумал решение, которое нашел здесь.

Я не уверен, что это хороший способ сделать это, но, по крайней мере, он сделал свою работу. Буду признателен, если кто-то сможет это оценить.

Я создал две функции, предложенные в ранее упомянутом ответе, и использовал их внутри постоянного хука beforeBulkDelete:

sequelize.addHook("beforeBulkDestroy", async options => {
      const query = await sequelize.query(`
      declare @RowId int = ${options.where.Id}
      declare @TableName sysname = '${options.model.name}'

      declare @Command varchar(max) 

      select @Command = isnull(@Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) + 
          ''' where exists(select * from ' + object_name(parent_object_id) + 
          CASE
              WHEN EXISTS(select object_name(object_id) from sys.columns col where name = 'deletedAt' and object_id = parent_object_id) 
                  THEN ' where ' + col.name+ ' = ' + cast(@RowId as varchar) +' and deletedAt IS NULL '
              when dbo.ParentIdFromTable(object_name(parent_object_id)) <> ''
                  then ' inner join ' + dbo.ParentIdFromTable(object_name(parent_object_id)) + ' on id = ' + dbo.PrimaryKey(object_name(parent_object_id))
                      +' where ' + col.name+ ' = ' + cast(@RowId as varchar) +' and deletedAt IS NULL '
              else 
                  ' where ' + col.name+ ' = ' + cast(@RowId as varchar) 
            END
          + ')' 
      from sys.foreign_key_columns fkc
          join sys.columns col on
              fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id
      where object_name(referenced_object_id) = @TableName

      PRINT @Command
      execute (@Command)
      `,
        { type: sequelize.QueryTypes.SELECT, logging: false }
      );

      if (query.length !== 0) throw new Error();
    });
person Vítor Cardoso Bertolucci    schedule 05.02.2020