'Sequelize Association called with something that's not a subclass of Sequelize.Model
I'm having error "...called with something that's not a subclass of Sequelize.Model" when I add association of Sequelize in my model it called error that what I call is not 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)
Here's my Code for
model/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;
model/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;
is there something I missed of? I've try to use this url https://dreamdevourer.com/example-of-sequelize-associations-in-feathersjs/
for adding assosicate along with model, but still having the same problem.
Much thanks for your help
Solution 1:[1]
Putting
A.hasOne(B)
and
B.belongsTo(A) in the same file solved the issue for me.
Solution 2:[2]
You need to add your associations in a function called associate(models). The models argument contains all your existing Model definitions keyed by their definition name ("user_tm" in this case).
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'});
};
Solution 3:[3]
Just for future googlers, this can also happen with code that looks right but there's a circular dependency. In my case, A had a belongsTo relationship to B, and when I added a hook at B that instantiated A, the error appeared (in fact, it appears as you add the import).
I fixed it by adding the hook at A file.
Solution 4:[4]
This is how I solved it: A.hasMany(models.B); on the A model then on B model B.belongsTo(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;
};
Solution 5:[5]
Putting all your models in one file isn't feasible if you have a lot of models.
What worked for me is not adding the models to the same file, but creating a new associations file and importing the models, then doing the belongsTo etc. in there. Then import './assocations' in the main app file. This resolved the error.
associations file would be something along the lines of this:
import {Post} from "./post";
import {Tag} from "./tag";
Tag.belongsToMany(Post, {
through: 'PostTags'
})
Post.belongsToMany(Tag, {
through: 'PostTags'
})
Solution 6:[6]
i found problem i forgot remove s from model name
User.belongsToMany(models.Roles, { through: "user_roles", });
Solution 7:[7]
If you add multiple associations at the same time it may mess up the process. In my case I removed all the associations and added them one by one ending up with the same code that was producing this error before but works fine now.
Solution 8:[8]
None of these worked for me.
The reason I get error was
Employee.js
const Company = require('./Company'); // you need to remove this line
var Employee = sequelize.define('employee', {
//define it
});
module.exports = Employee
Company.js
const Employee = require('./Employee');
var Company = sequelize.define('company', {
//define it
});
Company.hasOne(Employee) // this line throws error.
Do not import Company in Employee's file!
It has been almost 4 years after question asked but it may help someone in the future.
Solution 9:[9]
I'm new to Sequelize. This approach may be naïve, but it solves the chicken/egg problem in my simple use case:
models/Dog.js
const {Model} = require('sequelize');
module.exports = function (sequelize) {
class Dog extends Model {}
setTimeout(() => {
Dog.hasMany(sequelize.models.Flea);
}, 0);
return Dog;
}
models/Flea.js
const {Model} = require('sequelize');
module.exports = function (sequelize) {
class Flea extends Model {}
setTimeout(() => {
Flea.belongsTo(sequelize.models.Dog);
}, 0);
return Flea;
}
models/index.js:
const sequelize = getConnectionSomehow();
const Dog = require('./Dog' )(sequelize);
const Flea = require('./Flea')(sequelize);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
