Связь Sequelize вызывается чем-то, что не является подклассом Sequelize.Model

У меня возникает ошибка "... вызванная чем-то, что не является подклассом Sequelize.Model", когда я добавляю ассоциацию Sequelize в мою модель, это вызывало ошибку: то, что я называю, не является Sequelize Model

E:...\Projects\WebApps\hr1\hr1\node_modules\sequelize\lib\associations\mixin.js:81
      throw new Error(this.name + '.' + Utils.lowercaseFirst(Type.toString()) + ' called with something that\'s not a subclass of Sequelize.Model');
      ^

Error: user_employee_tm.class BelongsTo extends Association {
  constructor(source, target, options) {
    super(source, target, options);

    this.associationType = 'BelongsTo';
    this.isSingleAssociation = true;
    this.foreignKeyAttribute = {};

    if (this.as) {
      this.isAliased = true;
      this.options.name = {
        singular: this.as
      };
    } else {
      this.as = this.target.options.name.singular;
      this.options.name = this.target.options.name;
    }

    if (_.isObject(this.options.foreignKey)) {
      this.foreignKeyAttribute = this.options.foreignKey;
      this.foreignKey = this.foreignKeyAttribute.name || this.foreignKeyAttribute.fieldName;
    } else if (this.options.foreignKey) {
      this.foreignKey = this.options.foreignKey;
    }

    if (!this.foreignKey) {
      this.foreignKey = Utils.camelizeIf(
        [
          Utils.underscoredIf(this.as, this.source.options.underscored),
          this.target.primaryKeyAttribute
        ].join('_'),
        !this.source.options.underscored
      );
    }

    this.identifier = this.foreignKey;

    if (this.source.rawAttributes[this.identifier]) {
      this.identifierField = this.source.rawAttributes[this.identifier].field || this.identifier;
    }

    this.targetKey = this.options.targetKey || this.target.primaryKeyAttribute;
    this.targetKeyField = this.target.rawAttributes[this.targetKey].field || this.targetKey;
    this.targetKeyIsPrimary = this.targetKey === this.target.primaryKeyAttribute;

    this.targetIdentifier = this.targetKey;
    this.associationAccessor = this.as;
    this.options.useHooks = options.useHooks;

    // Get singular name, trying to uppercase the first letter, unless the model forbids it
    const singular = Utils.uppercaseFirst(this.options.name.singular);

    this.accessors = {
      get: 'get' + singular,
      set: 'set' + singular,
      create: 'create' + singular
    };
  }

  // the id is in the source table
  injectAttributes() {
    const newAttributes = {};

    newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, {
      type: this.options.keyType || this.target.rawAttributes[this.targetKey].type,
      allowNull: true
    });

    if (this.options.constraints !== false) {
      const source = this.source.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey];
      this.options.onDelete = this.options.onDelete || (source.allowNull ? 'SET NULL' : 'NO ACTION');
      this.options.onUpdate = this.options.onUpdate || 'CASCADE';
    }

    Helpers.addForeignKeyConstraints(newAttributes[this.foreignKey], this.target, this.source, this.options, this.targetKeyField);
    Utils.mergeDefaults(this.source.rawAttributes, newAttributes);

    this.identifierField = this.source.rawAttributes[this.foreignKey].field || this.foreignKey;

    this.source.refreshAttributes();

    Helpers.checkNamingCollision(this);

    return this;
  }

  mixin(obj) {
    const methods = ['get', 'set', 'create'];

    Helpers.mixinMethods(this, obj, methods);
  }

  /**
   * Get the associated instance.
   *
   * @param {Object} [options]
   * @param {String|Boolean} [options.scope] Apply a scope on the related model, or remove its default scope by passing false.
   * @param {String} [options.schema] Apply a schema on the related model
   * @see {@link Model.findOne} for a full explanation of options
   * @return {Promise<Model>}
   */
  get(instances, options) {
    const association = this;
    const where = {};
    let Target = association.target;
    let instance;

    options = Utils.cloneDeep(options);

    if (options.hasOwnProperty('scope')) {
      if (!options.scope) {
        Target = Target.unscoped();
      } else {
        Target = Target.scope(options.scope);
      }
    }

    if (options.hasOwnProperty('schema')) {
      Target = Target.schema(options.schema, options.schemaDelimiter);
    }

    if (!Array.isArray(instances)) {
      instance = instances;
      instances = undefined;
    }

    if (instances) {
      where[association.targetKey] = {
        [Op.in]: instances.map(instance => instance.get(association.foreignKey))
      };
    } else {
      if (association.targetKeyIsPrimary && !options.where) {
        return Target.findByPk(instance.get(association.foreignKey), options);
      } else {
        where[association.targetKey] = instance.get(association.foreignKey);
        options.limit = null;
      }
    }

    options.where = options.where ?
      {[Op.and]: [where, options.where]} :
      where;

    if (instances) {
      return Target.findAll(options).then(results => {
        const result = {};
        for (const instance of instances) {
          result[instance.get(association.foreignKey, {raw: true})] = null;
        }

        for (const instance of results) {
          result[instance.get(association.targetKey, {raw: true})] = instance;
        }

        return result;
      });
    }

    return Target.findOne(options);
  }

  /**
   * Set the associated model.
   *
   * @param {Model|String|Number} [newAssociation] An persisted instance or the primary key of an instance to associate with this. Pass `null` or `undefined` to remove the association.
   * @param {Object} [options] Options passed to `this.save`
   * @param {Boolean} [options.save=true] Skip saving this after setting the foreign key if false.
   * @return {Promise}
   */
  set(sourceInstance, associatedInstance, options) {
    const association = this;

    options = options || {};

    let value = associatedInstance;
    if (associatedInstance instanceof association.target) {
      value = associatedInstance[association.targetKey];
    }

    sourceInstance.set(association.foreignKey, value);

    if (options.save === false) return;

    options = _.extend({
      fields: [association.foreignKey],
      allowNull: [association.foreignKey],
      association: true
    }, options);

    // passes the changed field to save, so only that field get updated.
    return sourceInstance.save(options);
  }

  /**
   * Create a new instance of the associated model and associate it with this.
   *
   * @param {Object} [values]
   * @param {Object} [options] Options passed to `target.create` and setAssociation.
   * @see {@link Model#create}  for a full explanation of options
   * @return {Promise}
   */
  create(sourceInstance, values, fieldsOrOptions) {
    const association = this;

    const options = {};

    if ((fieldsOrOptions || {}).transaction instanceof Transaction) {
      options.transaction = fieldsOrOptions.transaction;
    }
    options.logging = (fieldsOrOptions || {}).logging;

    return association.target.create(values, fieldsOrOptions).then(newAssociatedObject =>
      sourceInstance[association.accessors.set](newAssociatedObject, options)
    );
  }
} called with something that's not a subclass of Sequelize.Model
    at Function.<anonymous> (E:...\Projects\WebApps\hr1\hr1\node_modules\sequelize\lib\associations\mixin.js:81:13)
    at Object.<anonymous> (E:...\Projects\WebApps\hr1\hr1\models\user_employee.js:22:14)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Module.require (internal/modules/cjs/loader.js:636:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (E:...\Projects\WebApps\hr1\hr1\models\user.js:4:26)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Module.require (internal/modules/cjs/loader.js:636:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (E:...\Projects\WebApps\hr1\hr1\routes\index.js:4:12)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)

Вот мой код для

модель / User.js

var bcrypt =  require('bcrypt');
const sequelize = require('../config/connectionDatabase')
var Sequelize = require('sequelize');
const UserEmployee = require('../models/user_employee');

var User = sequelize.define('user_tm', {
    NameFirst: {
        type: Sequelize.STRING
    },
    NameLast: {
        type: Sequelize.STRING
    },
    username: {
        type: Sequelize.STRING,
        unique: true,
        allowNull: false
    },
    password: {
        type: Sequelize.STRING,
        allowNull: false
    }
}, {
    hooks: {
    beforeCreate: (user) => {
        const salt = bcrypt.genSaltSync();
        user.password = bcrypt.hashSync(user.password, salt);
    }
    },
    instanceMethods: {
    validPassword: function(password) {
        return bcrypt.compareSync(password, this.password);
    }
    }    
});

User.hasOne(UserEmployee, {foreignKey: 'UserID', as: 'User'});
User.prototype.validPassword = function (password) {
    return bcrypt.compareSync(password, this.password);
};
module.exports = User;

модель / user_employee.js

const sequelize = require('../config/connectionDatabase');
var Sequelize = require('sequelize');
const User = require('../models/user');

var UserEmployee = sequelize.define('user_employee_tm', {
    DateJoin: {
        type: Sequelize.DATE
    },
    UserID: {
        type: Sequelize.INTEGER,
        references: {
            model: User,
            key: "ID"
        }
    },
    CompanyID: {
        type: Sequelize.INTEGER
    }
});

// UserEmployee.hasOne(User, {as: 'User', foreignKey: 'UserID'});  
UserEmployee.belongsTo(User , {foreignKey: 'ID', as: 'Employee'});
module.exports = UserEmployee;

я что-то упустил? Я пытаюсь использовать этот URL https://dreamdevourer.com/example-of-sequelize-associations-in-feathersjs/

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

Большое спасибо за вашу помощь

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
14
0
29 520
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Вам нужно добавить свои ассоциации в функцию под названием associate(models). Аргумент models содержит все ваши существующие определения Model с ключами по имени их определения (в данном случае "user_tm").

var User = sequelize.define('user_tm', {
  // ... user_tm definition
});

var UserEmployee = sequelize.define('user_employee_tm', {
  // ... user_employee_tm definition
});

UserEmployee.associate = (models) => {
  UserEmployee.belongsTo(models.user_tm, {foreignKey: 'ID', as: 'Employee'});
};

так мне нужно поместить определение UserEmployee в файл модели пользователя? Кроме того, у меня есть еще одно предупреждение {SequelizeEagerLoadingError: user_tm не связан с user_employee_tm!

Bagus Santoso 26.12.2018 06:08

вам также необходимо создать обратные отношения.

doublesharp 26.12.2018 21:29

Хочу добавить, что дело тоже немаловажное. Убедитесь, что имя определения точно такое же, как и в дальнейшем.

diogo 14.07.2020 21:38

Свойство associate не существует в TypeScript :(

Hiroki 02.02.2021 13:21
Ответ принят как подходящий

Оказывается, я обнаружил, что мне просто нужно определить свой объект UserEmployee. Вот код, который я исправил

const sequelize = require('../config/connectionDatabase');
var Sequelize = require('sequelize');
const User = require('../models/user');
const Company = require('../models/company');

var UserEmployee = sequelize.define('user_employee_tm', {
    DateJoin: {
        type: Sequelize.DATE
    },
    UserID: {
        type: Sequelize.INTEGER,
        references: {
            model: User,
            key: "UserID"
        }
    },
    CompanyID: {
        type: Sequelize.INTEGER,
        references: {
            model: Company,
            key: "CompanyID"
        }
    }
});
UserEmployee.belongsTo(Company, {as: 'Company', foreignKey: 'CompanyID'});
UserEmployee.belongsTo(User, {as: 'User', foreignKey: 'UserID'});
module.exports = UserEmployee;

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

Надеюсь, что другие, у кого такая же проблема со мной, могут позаботиться о нем, не делая 2 моделей в 1 файле.

P.S. Спасибо за doublesharp за вашу помощь, чтобы указать на мою ошибку

Только для будущих гуглеров это также может произойти с кодом, который выглядит правильно, но имеет циклическую зависимость. В моем случае у A было отношение ownTo к B, и когда я добавил ловушку в B, которая создавала экземпляр A, появилась ошибка (фактически, она появляется, когда вы добавляете import).

Я исправил это, добавив крючок в файл A.

Положив A.hasOne(B) и B.belongsTo(A) в том же файле решил проблему за меня.

Я могу подтвердить, что этот подход работает ... но действительно ли это хорошая идея? Для этого мы должны либо (1) поместить ассоциации (hasOne, belongsTo и т. д.) В один файл отдельно от определений моделей, либо (2) поместить ассоциации и определения моделей в один файл.

Hiroki 02.02.2021 13:33

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

atultw 14.03.2021 18:14

i found problem i forgot remove s from model name

User.belongsToMany (models.Roles, { через: "user_roles", });

Вот как я это решил: A.hasMany (models.B); на модели A, затем на модели B B. принадлежит к (models.A);

"use strict";
const { Model } = require("sequelize");
const quotation = require("./quotation");
module.exports = (sequelize, DataTypes) => {
  class Clients extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Clients.hasOne(models.Quotation);
    }
  }
  Clients.init(
    {
      firstName: DataTypes.STRING,
      lastName: DataTypes.STRING,
      email: DataTypes.STRING,
      phone: DataTypes.STRING,
      contactName: DataTypes.STRING,
      contactPosition: DataTypes.STRING,
      rncCode: DataTypes.STRING,
      active: DataTypes.BOOLEAN,
    },
    {
      sequelize,
      modelName: "Clients",
    }
  );

  return Clients;
};

"use strict";
const { Model } = require("sequelize");
const quotation = require("./quotation");
module.exports = (sequelize, DataTypes) => {
  class Clients extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Clients.hasOne(models.Quotation);
    }
  }
  Clients.init(
    {
      firstName: DataTypes.STRING,
      lastName: DataTypes.STRING,
      email: DataTypes.STRING,
      phone: DataTypes.STRING,
      contactName: DataTypes.STRING,
      contactPosition: DataTypes.STRING,
      rncCode: DataTypes.STRING,
      active: DataTypes.BOOLEAN,
    },
    {
      sequelize,
      modelName: "Clients",
    }
  );

  return Clients;
};

Сложить все ваши модели в один файл невозможно, если у вас много моделей.

Что сработало для меня, так это не добавление моделей в один и тот же файл, а создание нового файла associations и импорт моделей, а затем создание belongsTo и т. д. Там. Затем import './assocations' в основном файле приложения. Это устранило ошибку.

Файл associations будет примерно таким:

import {Post} from "./post";
import {Tag} from "./tag";

Tag.belongsToMany(Post, {
    through: 'PostTags'
})

Post.belongsToMany(Tag, {
    through: 'PostTags'
})

Я новичок в Sequelize. Этот подход может быть наивным, но он решает проблему курицы / яйца в моем простом случае использования:

модели / Dog.js

const {Model} = require('sequelize');

module.exports = function (sequelize) {
  class Dog extends Model {}

  setTimeout(() => {
    Dog.hasMany(sequelize.models.Flea);
  }, 0);

  return Dog;
}

модели / Flea.js

const {Model} = require('sequelize');

module.exports = function (sequelize) {
  class Flea extends Model {}

  setTimeout(() => {
    Flea.belongsTo(sequelize.models.Dog);
  }, 0);

  return Flea;
}

модели / index.js:

const sequelize = getConnectionSomehow();

const Dog  = require('./Dog' )(sequelize);
const Flea = require('./Flea')(sequelize);

Другие вопросы по теме