Relacionamento Um-para-Muitos (One-to-Many) com Sequelize no Node.js
Em um exemplo típico, em uma empresa podem trabalhar várias pessoas. Ou seja, temos um relacionamento um-para-muitos (1 empresa - muitos funcionários). Para criar esse tipo de relacionamento no Sequelize, utilizamos o método hasMany()
const Sequelize = require("sequelize");
// definindo o objeto Sequelize
const sequelize = new Sequelize({
dialect: "sqlite",
storage: "programicio.db",
define: {
timestamps: false
}
});
// definindo o modelo User
const User = sequelize.define("user", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
name: {
type: Sequelize.STRING,
allowNull: false
},
age: {
type: Sequelize.INTEGER,
allowNull: false
}
});
const Company = sequelize.define("company", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
name: {
type: Sequelize.STRING,
allowNull: false
}
});
Company.hasMany(User);
sequelize.sync({force:true}).then(()=>{
console.log("Tables have been created");
}).catch(err => console.log(err));
O método hasMany()
Company
User
Como resultado, o SQLite criará duas tabelas que serão descritas pelo seguinte código SQL:
CREATE TABLE IF NOT EXISTS `companies` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` VARCHAR(255) NOT NULL
);
CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` VARCHAR(255) NOT NULL,
`age` INTEGER NOT NULL,
`companyId` INTEGER REFERENCES `companies` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
);
Por padrão, na tabela dependente users
companyId
users
companies
Neste código, vemos que, ao excluir um objeto da tabela companies
users
companyId
NULL
ON DELETE SET NULL
hasMany()
onDelete
Company.hasMany(User, { onDelete: "cascade" });
Operações Básicas
Agora vamos explorar algumas operações básicas que podem causar dúvidas ao trabalhar com modelos em um relacionamento um-para-muitos.
Ao criar um objeto do modelo dependente, muitas vezes é necessário especificar a referência ao modelo principal relacionado. Para isso, podemos usar a propriedade da model que corresponde ao nome do campo da chave estrangeira na tabela correspondente. No exemplo acima, na tabela users
companyId
companies
Company
// criando uma empresa
Company.create({ name: "Microsoft"}).then(res => {
// obtendo o id da empresa criada
const compId = res.id;
// criando dois funcionários para essa empresa
User.create({name:"Tom", age: 39, companyId: compId}).catch(err => console.log(err));
User.create({name:"Alice", age: 36, companyId: compId}).catch(err => console.log(err));
}).catch(err => console.log(err));
Há outra maneira de adicionar um objeto dependente: por meio da model principal. A model principal possui, implicitamente, um método chamado createNomeDoModeloDependente()
createUser()
// encontrar a empresa com id=1
Company.findByPk(1).then(company => {
if (!company) return console.log("Company not found");
console.log(company);
// adicionando um objeto para esta empresa
company.createUser({name:"Bob", age: 43}).catch(err => console.log(err));
}).catch(err => console.log(err));
Na prática, a única diferença em relação à primeira abordagem de criação é que, neste caso, não é necessário especificar o id
Para obter todos os objetos dependentes relacionados à model principal, existe o método getNomeDosModelosDependentes
getUsers()
id=1
Company.findByPk(1).then(company => {
if (!company) return console.log("Company not found");
company.getUsers()
.then(users => {
for (user of users)
console.log(user.name, " - ", company.name);
})
.catch(err => console.log(err));
}).catch(err => console.log(err));
Saída no console:
Tom - Microsoft Alice - Microsoft Bob - Microsoft
Todas as outras operações com modelos dependentes relacionados podem ser realizadas da mesma forma que com modelos independentes.