Reputation: 481
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
Upvotes: 26
Views: 73036
Reputation: 1
This is for those recently having this issue, might not be perfect code, but it works.
I am quite new to sequelize and all, so I did this. I have multiple files for the schema and I am sucker for structured code and trying to learn the clean code model, emphasis on "trying", so this is what I could come up with, it stopped giving the error and quite works as expected, excited to share with everyone.
const { DataTypes } = require('sequelize');
const ContactInfo = require('./ContactInfo');
const User = require('./User');
const BlogPost = require('./BlogPost');
module.exports.associations = (sequelize) => {
const user = User(sequelize);
const contactInfo = ContactInfo(sequelize);
const blogpost = BlogPost(sequelize);
// Define your associations here
// One-to-one relationship
user.hasOne(contactInfo, {
foreignKey: {
type: DataTypes.UUID,
allowNull: false,
},
});
contactInfo.belongsTo(user);
// One-to-many relationship
user.hasMany(blogpost, {
foreignKey: {
type: DataTypes.UUID,
allowNull: false,
},
});
blogpost.belongsTo(user);
// Many-to-many relationship
user.belongsToMany(user, {
as: 'User',
foreignKey: 'UserId',
through: 'Follow',
});
user.belongsToMany(user, {
as: 'Followed',
foreignKey: 'FollowedId',
through: 'Follow',
});
};
Upvotes: 0
Reputation: 180
Print typeof Entity
where Entity
is what Sequelize does not recognize as a model.
If you get undefined
in the console, chances are that Entity
is being exported incorrectly. For example, my problem was a typo: I wrote module.export
instead of module.exports
Using Associate
was not necessary in my case: for a many-to-many relationship, I used:
const EventReportCategory_EventReport = database.define(
"event_report_category_event_report",
{});
EventReport.belongsToMany(EventReportCategory,
{
through: EventReportCategory_EventReport
});
EventReportCategory.belongsToMany(EventReport,
{
through: EventReportCategory_EventReport
});
As soon as you wrap the mapping (in this case, a many-to-many mapping) in a function, and you call it before syncrhonizing Sequelize (new Sequelize(...).sync()
), it is not necessary to define the entities in the same file where you do the mapping. In the previous example, EventReport
and EventReportCategory
are defined in different files.
Upvotes: 0
Reputation: 62
when I got this error, it happened that I defined my model using the class method. And I got a spelling error in some of the model files. I knew it was a spelling error when I consoled.log(models).
I just corrected the spelling and it fixes it.
static associate(models) {
// define association here
console.log(models,'-=====')
Category.belongsToMany(models.service, {through: 'serviceCategory'})
Category.belongsToMany(models.Job, {through: 'JobCategory'})
}
Upvotes: 2
Reputation: 427
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.
Upvotes: 2
Reputation: 1
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.
Upvotes: 0
Reputation: 212
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);
Upvotes: -1
Reputation: 1021
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'
})
Upvotes: 5
Reputation: 49
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;
};
Upvotes: 4
Reputation: 29
i found problem i forgot remove s from model name
User.belongsToMany(models.Roles, { through: "user_roles", });
Upvotes: 0
Reputation:
Putting
A.hasOne(B)
and
B.belongsTo(A)
in the same file solved the issue for me.
Upvotes: 40
Reputation: 3573
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.
Upvotes: 8
Reputation: 27677
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'});
};
Upvotes: 13
Reputation: 481
Turns out I've found that I just need to define my Object of UserEmployee Here's the code that I've Fixed
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;
no need to set as associate due to Sequelize has set method associate them, and I've also fix the relation of it.
hope others that has same problem with me could look after it, without make 2 models ends up on 1 file.
P.S. Thanks for doublesharp for your help to point my wrong doing
Upvotes: 7