SequelizeForeignKeyConstraintError: обновление или удаление в таблице X нарушает ограничение внешнего ключа fkey в таблице Y

#javascript #database #postgresql #sequelize.js

Вопрос:

У меня возникла проблема с обновлением отображаемого имени в таблице пользователей со следующей ошибкой.

ОТНОШЕНИЯ

Пользователь также может быть супервайзером. И обе таблицы имеют поле имени (отображаемое имя пользователя и имя руководителя). Если пользователь X отредактирует свой профиль и изменит имя дисплея, я хочу, чтобы это изменение отразилось в поле имя таблицы супервизора. Я думал, что каскад будет работать, но я его не получал.

 (node:25136) UnhandledPromiseRejectionWarning: SequelizeForeignKeyConstraintError: update or delete on table "c_user" violates foreign key constraint "c_supervisor_name_fkey" on table "c_supervisor"
 

Существует соотношение 1:n между таблицей пользователей и таблицей супервизора.

МОДЕЛЬ ПОЛЬЗОВАТЕЛЯ

   const User = sequelize.define('user', {
    id: {
      type: Sequelize.INTEGER,
      allowNull: false,
      primaryKey: true,
      autoIncrement: true
    },
    displayName: {
      type: Sequelize.STRING,
      allowNull: false,
      unique: true
    },

  User.associate = function(models) {
    User.hasOne(models.supervisor, { foreignKey: "userId" });
  };
    User.hasOne(models.supervisor, { foreignKey: "name" });
    
 return User;
};

 

МОДЕЛЬ СУПЕРВАЙЗЕРА

 module.exports = (sequelize, Sequelize) => {
  const Supervisor = sequelize.define('supervisor', {
    id: {
       type: Sequelize.INTEGER,
       allowNull: false,
       primaryKey: true,
       autoIncrement: true
     },
    userId: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      allowNull: false,
      unique: true,
      references: {
        model: 'c_user',
        key: 'id'
      }
    },
    name: {
      type: Sequelize.STRING,
      allowNull: false,
      references: {
        model: 'c_user',
        key: 'displayName'
      }
    },

Supervisor.associate = function(models) {
    Supervisor.belongsTo(models.user, {
      foreignKey: "userId", targetKey: "id", onDelete: "CASCADE", onUpdate: "CASCADE"
    });
    Supervisor.belongsTo(models.user, {
      foreignKey: "name", targetKey: "displayName", onDelete: "CASCADE", onUpdate: "CASCADE"
    });
  }
  
  return Supervisor;
};
 

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

Комментарии:

1. Почему название вообще имеет отношение к отношению?

2. @Andreas у пользователя есть страница профиля, где он может редактировать свое отображаемое имя. Затем у того же пользователя есть поле имени в модели супервизора. Поэтому мы хотим, чтобы, если пользователь изменит имя в модели пользователя, это изменение должно немедленно отразиться в модели супервизора.

3. Это не ответ на мой вопрос. Почему имя хранится в двух местах? И почему он используется в отношениях? Связь строится с идентификатором. Это оно.

4. @Andreas В контроллере супервайзера я использовал идентификатор пользователя для получения отображаемого имени пользователя и использовал его в качестве имени. Во внешнем интерфейсе при заполнении формы супервайзера пользователю нужно только указать идентификатор пользователя. Там нет ввода для имени, которое обрабатывается в бэкэнде. Даже когда я удаляю связь с именем и просто использую идентификатор пользователя для получения имени дисплея, я все равно получаю описанную выше ошибку при попытке обновить имя пользователя.

Ответ №1:

Во-первых, использовать имя в качестве иностранного ключа-плохая идея. И во-вторых, если вы связываете две одинаковые таблицы друг с другом, вам нужно использовать псевдонимы, чтобы различать, как они связаны. Например:

 // user-to-supervisor one to one relation as user
User.hasOne(Supervisor, {foreignKey: 'userId', as: 'user'})
Supervisor.belongsTo(User)
// user-to-supervisor one to one relation as username
User.hasOne(Supervisor, {foreignKey: 'name', as: 'username'})
Supervisor.belongsTo(User)
 

Надеюсь, это поможет, но то, что вы пытаетесь сделать, непрактично.
Можете ли вы рассказать более конкретно об отношениях, которых вы пытаетесь достичь?

Комментарии:

1. Пользователь также может быть супервайзером. И обе таблицы имеют поле имени (отображаемое имя пользователя и имя руководителя). Если пользователь X отредактирует свой профиль и изменит имя дисплея, я хочу, чтобы это изменение отразилось в поле имя таблицы супервизора. Я думал, что каскад будет работать, но я его не получал.

2. @Wacademy вы можете создать только одну модель пользователя и добавить новое поле под названием роль, в котором может быть пользователь, супервайзер.

3. В моей пользовательской модели уже есть роли, но супервизор-это отдельная модель, а не роль. Спасибо