I try to explain my case. I have two models: Film
and Category
. They are N:M associations.
migration file 20200123070411-createTables.js
:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Category', {
ID: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
Name: {
type: Sequelize.STRING(20),
allowNull: false,
},
Last_Update: {
type: Sequelize.DATE,
allowNull: false,
},
});
await queryInterface.createTable('Language', {
ID: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
Name: {
type: Sequelize.STRING(20),
allowNull: false,
},
Last_Update: {
type: Sequelize.DATE,
allowNull: false,
},
});
await queryInterface.createTable('Film', {
ID: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
LanguageID: {
type: Sequelize.INTEGER,
references: {
model: 'Language',
key: 'ID',
},
onDelete: 'restrict',
allowNull: false,
},
Title: {
type: Sequelize.STRING,
allowNull: false,
},
Description: {
type: Sequelize.STRING,
allowNull: false,
},
Release_Year: {
type: Sequelize.INTEGER,
allowNull: false,
},
Rental_Duration: {
type: Sequelize.INTEGER,
allowNull: false,
},
Rental_Date: {
type: Sequelize.DECIMAL(19, 0),
allowNull: false,
},
Length: {
type: Sequelize.INTEGER,
allowNull: false,
},
Replacement_Cost: {
type: Sequelize.DECIMAL(19, 0),
allowNull: false,
},
Rating: {
type: Sequelize.INTEGER,
allowNull: false,
},
Last_Update: {
type: Sequelize.DATE,
allowNull: false,
},
Special_Features: {
type: Sequelize.STRING,
allowNull: false,
},
Fulltext: {
type: Sequelize.STRING,
allowNull: false,
},
});
await queryInterface.createTable(
'Film_Category',
{
FilmID: {
type: Sequelize.INTEGER,
// composite primary key
primaryKey: true,
references: {
model: 'Film',
key: 'ID',
},
onDelete: 'restrict',
},
CategoryID: {
type: Sequelize.INTEGER,
primaryKey: true,
references: {
model: 'Category',
key: 'ID',
},
onDelete: 'cascade',
},
Last_Update: {
type: Sequelize.DATE,
allowNull: false,
},
}
);
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Film_Category');
await queryInterface.dropTable('Film');
await queryInterface.dropTable('Category');
await queryInterface.dropTable('Language');
},
};
After executing the db migration, I define models below:
models/category.ts
:
import { Model, DataTypes, BelongsToManyGetAssociationsMixin } from 'sequelize';
import { sequelize } from '../db';
import { Film } from './film_category';
class Category extends Model {
public ID!: number;
public Name!: string;
public Last_Update!: Date;
public getFilms!: BelongsToManyGetAssociationsMixin<Film>;
}
Category.init(
{
ID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
Name: {
type: DataTypes.STRING(20),
allowNull: false,
},
Last_Update: {
type: DataTypes.DATE,
allowNull: false,
},
},
{ sequelize, modelName: 'Category' },
);
export { Category };
models/film.ts
:
import { Model, DataTypes, BelongsToManyGetAssociationsMixin } from 'sequelize';
import { sequelize } from '../db';
import { Category } from './film_category';
class Film extends Model {
public ID!: number;
public LanguageID!: number;
public Title!: string;
public Description!: string;
public Release_Year!: number;
public Rental_Duration!: number;
public Rental_Date!: number;
public Length!: number;
public Replacement_Cost!: number;
public Rating!: number;
public Last_Update!: Date;
public Special_Features!: string;
public Fulltext!: string;
public getCategories!: BelongsToManyGetAssociationsMixin<Category>;
}
Film.init(
{
ID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
LanguageID: {
type: DataTypes.INTEGER,
references: {
model: 'Language',
key: 'ID',
},
onDelete: 'restrict',
allowNull: false,
},
Title: {
type: DataTypes.STRING,
allowNull: false,
},
Description: {
type: DataTypes.STRING,
allowNull: false,
},
Release_Year: {
type: DataTypes.INTEGER,
allowNull: false,
},
Rental_Duration: {
type: DataTypes.INTEGER,
allowNull: false,
},
Rental_Date: {
type: DataTypes.DECIMAL(19, 0),
allowNull: false,
},
Length: {
type: DataTypes.INTEGER,
allowNull: false,
},
Replacement_Cost: {
type: DataTypes.DECIMAL(19, 0),
allowNull: false,
},
Rating: {
type: DataTypes.INTEGER,
allowNull: false,
},
Last_Update: {
type: DataTypes.DATE,
allowNull: false,
},
Special_Features: {
type: DataTypes.STRING,
allowNull: false,
},
Fulltext: {
type: DataTypes.STRING,
allowNull: false,
},
},
{ sequelize, modelName: 'Film' },
);
export { Film };
models/film_category.ts
:
import { Model, DataTypes } from 'sequelize';
import { sequelize } from '../db';
import { Category } from './category';
import { Film } from './film';
class FilmCategory extends Model {
public FilmID!: number;
public CategoryID!: number;
public Last_Update!: Date;
}
FilmCategory.init(
{
FilmID: {
type: DataTypes.INTEGER,
primaryKey: true,
references: {
model: 'Film',
key: 'ID',
},
onDelete: 'restrict',
},
CategoryID: {
type: DataTypes.INTEGER,
primaryKey: true,
references: {
model: 'Category',
key: 'ID',
},
onDelete: 'cascade',
},
Last_Update: {
type: DataTypes.DATE,
allowNull: false,
},
},
{ sequelize, modelName: 'Film_Category' },
);
export { FilmCategory, Film, Category };
models/index.ts
:
import { Category } from './category';
import { Film } from './film';
import { Language } from './language';
import { FilmCategory } from './film_category';
Category.belongsToMany(Film, { through: FilmCategory });
Film.belongsToMany(Category, { through: FilmCategory });
Language.hasMany(Film);
export { Category, Film, Language, FilmCategory };
When I try to call Film.findByPk(1)
, sequelize
throw an error:
SequelizeDatabaseError: column "CategoryID" does not exist
The SQL query generated by sequelize
of Film.findByPk(1)
like this:
Executing (default): SELECT "ID", "LanguageID", "Title", "Description", "Release_Year", "Rental_Duration", "Rental_Date", "Length", "Replacement_Cost", "Rating", "Last_Update", "Special_Features", "Fulltext", "CategoryID" FROM "Film" AS "Film" WHERE "Film"."ID" = 1;
I know when I use Film.belongsToMany(Category, { through: FilmCategory });
, sequelize
will add CategoryID
of target model Category
to source model Film
. I expect the film data find by primary key has the same properties as the model schema. This extra CategoryID
column is the issue.
So I don't want this CategoryID
column to be added on Film
model and FilmID
column to be added on Category
model. Because Film
table doesn't have CategoryID
column and Category
table doesn't have FilmID
column in the database. They are connected by the join table Film_Category
. Is there any way to do this? Or, am I missing something?
Created a minimal reproducible code repo: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/db
Should work if you explicitly define the 'through' table in the association, like so:
Film.belongsToMany(Category,
{
through: FilmCategory,
foreignKey: 'FilmID',
otherKey: 'CategoryID'
});
It's possible the problems may occurs because you're using ID rather than Id, but that is just speculation...
HTH
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.