Запретить сиквелизирование от мягкого удаления строк, на которые есть ссылки в другом месте - PullRequest
1 голос
/ 04 февраля 2020

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

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

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

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

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

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

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

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

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

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

1 Ответ

0 голосов
/ 05 февраля 2020

Итак, я нашел решение, которое нашел здесь .

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

Я создал две функции, предложенные в ранее упомянутом ответе, и использовал их внутри 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();
    });
...