SequelizeDatabaseError: Не удалось создать ограничение или индекс при отправке миграции в базу данных SQL Azure. - PullRequest
0 голосов
/ 23 октября 2019

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

Sequelize CLI [Node: 10.15.3, CLI: 5.5.1, ORM: 5.19.2]

Loaded configuration file "config\config.json".
Using environment "development".
(node:16208) [SEQUELIZE0004] DeprecationWarning: A boolean value was passed to options.operatorsAliases. This is a no-op with v5 and should be removed.
== 20191003000554-create-user: migrating =======
== 20191003000554-create-user: migrated (0.141s)

== 20191003012530-create-workshop: migrating =======
== 20191003012530-create-workshop: migrated (0.131s)

== 20191003012716-create-location: migrating =======
== 20191003012716-create-location: migrated (0.219s)

== 20191003012841-create-instructor: migrating =======
== 20191003012841-create-instructor: migrated (0.163s)

== 20191003013038-create-notification: migrating =======
== 20191003013038-create-notification: migrated (0.162s)

== 20191022001209-create-class: migrating =======
== 20191022001209-create-class: migrated (0.135s)

== 20191022001540-add-associations: migrating =======

ERROR: SequelizeDatabaseError: Could not create constraint or index. See previous errors.
    at Query.formatError (C:\Users\Ryan\Desktop\sddec19-04\node_modules\sequelize\lib\dialects\mssql\query.js:314:12)
    at Request.connection.lib.Request [as userCallback] (C:\Users\Ryan\Desktop\sddec19-04\node_modules\sequelize\lib\dialects\mssql\query.js:74:23)
    at Request.callback (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\request.js:37:27)
    at Connection.endOfMessageMarkerReceived (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\connection.js:2104:20)
    at Connection.dispatchEvent (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\connection.js:1084:36)
    at Parser.tokenStreamParser.on (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\connection.js:914:14)
    at Parser.emit (events.js:189:13)
    at Parser.parser.on.token (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\token\token-stream-parser.js:27:14)
    at Parser.emit (events.js:189:13)
    at addChunk (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_readable.js:297:12)
    at readableAddChunk (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_readable.js:279:11)
    at Parser.Readable.push (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_readable.js:240:10)
    at Parser.Transform.push (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_transform.js:139:32)
    at Parser.afterTransform (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_transform.js:88:10)
    at Parser._transform (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\token\stream-parser.js:41:7)
    at Parser.Transform._read (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_transform.js:177:10)
    at Parser.Transform._write (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_transform.js:164:83)
    at doWrite (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_writable.js:405:139)
    at writeOrBuffer (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_writable.js:394:5)
    at Parser.Writable.write (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\node_modules\readable-stream\lib\_stream_writable.js:303:11)
    at Parser.addEndOfMessageMarker (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\token\token-stream-parser.js:45:24)
    at Connection.message (C:\Users\Ryan\Desktop\sddec19-04\node_modules\tedious\lib\connection.js:2093:32)

Я рассмотрел некоторые другие вопросы здесь, ноНи одно из них не имеет прямого отношения к тому, что я вижу.

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

Вот моя модель длятаблица Users

'use strict';
module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    Role: DataTypes.STRING,
    FirstName: DataTypes.STRING,
    LastName: DataTypes.STRING,
    Email: DataTypes.STRING,
    Password: DataTypes.STRING,
    EmployedDate: DataTypes.STRING
  }, {});
  User.associate = function(models) {
    User.hasMany(models.Instructor, as: 'ManagerId');
    User.hasMany(models.Notification, as: 'UserId');
    User.hasMany(models.Workshop, as: 'CreatorId');
    User.hasMany(models.Notification, as: 'RequesterId');
  };
  return User;
};

Вот моя модель для таблицы Instructors

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Instructor = sequelize.define('Instructor', {
    CertificationLevel: DataTypes.STRING,
    CPRCertificationDate: DataTypes.DATE,
    StrengthTrainingLevel: DataTypes.STRING,
    KettelbellLevel: DataTypes.STRING,
    ClassesTaught: DataTypes.INTEGER,
    UserId: DataTypes.INTEGER,
    ManagerId: DataTypes.INTEGER,
    MostRecentWorkshopId: DataTypes.INTEGER,
  }, {});
  Instructor.associate = function(models) {
    Instructor.belongsTo(models.User, as: 'UserId');
    Instructor.hasMany(models.Workshop, as: 'InstructorId');
    Instructor.belongsTo(models.Workshop, as: 'MostRecentWorkshopId');
    Instructor.hasMany(models.Class, as: 'InstructorId');
  };
  return Instructor;
};

Вот моя модель для таблицы Locations

'use strict';
module.exports = (sequelize, DataTypes) => {
  const Location = sequelize.define('Location', {
    LocationName: DataTypes.STRING,
    Address: DataTypes.STRING,
    City: DataTypes.STRING,
    State: DataTypes.STRING,
    ZipCode: DataTypes.INTEGER,
    Region: DataTypes.STRING,
    Latitude: DataTypes.FLOAT,
    Longitude: DataTypes.FLOAT,
    PhoneNumber: DataTypes.STRING,
    MainContact: DataTypes.STRING,
    Owners: DataTypes.STRING,
    Email: DataTypes.STRING
  }, {});
  Location.associate = function(models) {
    Location.hasMany(models.Workshop, as: 'LocationId');
  };
  return Location;
};

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

Вот моя миграция, которая выполняет все ассоциации. Он запускается последним из всех файлов миграции.

module.exports = {
  up: (queryInterface, Sequelize) => {
    // Instructor belongsTo User (itself)
    return queryInterface.addColumn(
      'Instructors', // Name of the Source model
      'UserId', // Name of the key we are adding
      {
        type: Sequelize.INTEGER,
        references: {
          model: 'Users', // Name of the Target model
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      }
    ).then(() => {
      // Manager (User) hasMany Instructors below them
      return queryInterface.addColumn(
        'Instructors', // Name of the Target model
        'ManagerId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Users', // Name of the Source model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // User hasMany Notifications
      return queryInterface.addColumn(
        'Notifications', // Name of the Target model
        'UserId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Users', // Name of the Source model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // User hasMany Workshops that they might have created
      return queryInterface.addColumn(
        'Workshops', // Name of the Target model
        'CreatorId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Users', // Name of the Source model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // Instructor hasMany Workshops that they might lead
      return queryInterface.addColumn(
        'Workshops', // Name of the Target model
        'InstructorId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Instructors', // Name of the Source model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // Location hasMany Workshops that can be located there
      return queryInterface.addColumn(
        'Workshops', // Name of the Target model
        'LocationId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Locations', // Name of the Source model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // Instructor belongsTo their most recent workshop
      return queryInterface.addColumn(
        'Instructors', // Name of the Source model
        'MostRecentWorkshopId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Workshops', // Name of the Target model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // User hasMany Notifiactions that are related to them
      return queryInterface.addColumn(
        'Notifications', // Name of the Target model
        'RequesterId', // Name of the key we are adding
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Users', // Name of the Source model
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    }).then(() => {
      // Instructor hasMany Classes that they might have taught
      return queryInterface.addColumn(
        'Classes',
        'InstructorId',
        {
          type: Sequelize.INTEGER,
          references: {
            model: 'Instructors',
            key: 'id',
          },
          onUpdate: 'CASCADE',
          onDelete: 'SET NULL',
        }
      );
    });
  },

  down: (queryInterface, Sequelize) => {
    // Remove UserId column
    return queryInterface.removeColumn(
      'Instructors', // Name of Source model
      'UserId' // Name of column to delete
    ).then(() => {
      // Remove ManagerId column
      return queryInterface.removeColumn(
        'Instructors', // Name of Target model
        'ManagerId' // Name of column to delete
      );
    }).then(() => {
      // Remove UserId column
      return queryInterface.removeColumn(
        'Notifications',
        'UserId'
      );
    }).then(() => {
      // Remove CreatorId column
      return queryInterface.removeColumn(
        'Workshops',
        'CreatorId'
      );
    }).then(() => {
      // Remove InstructorId column
      return queryInterface.removeColumn(
        'Workshops',
        'InstructorId'
      );
    }).then(() => {
      // Remove LocationId column
      return queryInterface.removeColumn(
        'Workshops',
        'LocationId'
      );
    }).then(() => {
      // Remove MostRecentWorkshopId column
      return queryInterface.removeColumn(
        'Instructors',
        'MostRecentWorkshopId'
      );
    }).then(() => {
      // Remove RequesterId column
      return queryInterface.removeColumn(
        'Notifications',
        'RequesterId'
      );
    }).then(() => {
      // Remove InstructorId column
      return queryInterface.removeColumn(
        'Classes',
        'InstructorId'
      );
    });
  }
};

Кажется, что происходит, когда определяется первая связь между Инструкторами и Пользователями, но затем появляется ошибка, когда запускается следующая связь.

Этот файл работал нормально, когда я запускал его в своей локальной базе данных MySQL. Может ли быть так, что SQL Server не разрешает эти множественные ассоциации / циклические ассоциации? Например, потому что два разных столбца в таблице «Инструкторы» имеют ссылки на «id» в Users?

Нужно ли вообще столько ассоциаций?

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

...