Например, в одной компании может работать несколько человек. То есть мы имеем отношение одни-ко-многим (1 компания - много сотрудников). Для создания подобной связи в Sequelize применяется метод hasMany(). Например:
const Sequelize = require("sequelize"); // определяем объект Sequelize const sequelize = new Sequelize({ dialect: "sqlite", storage: "metanit.db", define: { timestamps: false } }); // определяем модель 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));
Метод hasMany() вызывается именно у главной модели - Company. А в сам метод передается зависимая модели - User.
В итоге в базе данных SQLite будут созданы две таблицы, которые описываются следующим 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 );
По умолчанию в зависимой таблице (то есть users) будет создаваться дополнительный столбец, который называтся по имени главной модели плюс суффикс "Id", то есть в данном случае companyId. И через данный столбец строка из companies сможет ссылаться на объект из таблицы users.
В данном случае в коде для таблицы users мы видим, что при удалении главного объекта из таблицы companies зависимый объекты из таблицы users не удаляются -
в столбце companyId для таких строк будет устанавливаться значение NULL, поскольку действует выражение ON DELETE SET NULL
. Однако
нередко более распространнной стратегией является каскадное удаление - при удалении главного объекта удаляются и все связанные с ним объекты. Для этого
в метод hasMany()
передается в качестве второго параметра специальный объект, который настраивает отношение между моделями. В частности,
параметр "onDelete"
позволяет задать действия при удалении:
Company.hasMany(User, { onDelete: "cascade" });
Рассмотим некоторые базовые операции, которые могут вызвать затруднения при работе с моделями со связью один-ко-многим.
При создании объекта зависимой модели нередко требуется указать ссылку на связанную главную модель. Для этого мы можем задействовать свойство модели, которое совпадает с именем столбца-внешнего ключа в соответствующей таблице. Например, в примере выше в таблице companies для связи с таблицей users создаваться столбец companyId. И хотя в модели Company выше явным образом не определено подобное свойство, но оно создается неявно. Например, создание объектов:
//создаем одну компанию Company.create({ name: "Microsoft"}).then(res=>{ // получаем id созданной компании const compId = res.id; //создаем пару сотрудников для этой компании 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));
Есть другой способ добавления зависимой модели - через главную модель. У главной модели для этого неявно определяется метод по имени createЗАВИСИМАЯ_МОДЕЛЬ()
(например, createUser()
):
// найдем компанию с id=1 Company.findByPk(1).then(company=>{ if(!company) return console.log("Company not found"); console.log(company); // и добавим для нее один объект company.createUser({name:"Bob", age: 43}).catch(err=>console.log(err)); }).catch(err=>console.log(err));
Фактически единственное отличие от первого варианта добавления состоит в том, что в данном случае не надо указывать id главной модели.
Для получения всех связанных объектов зависимой модели у главной модели определяется метод по имени getЗАВИСИМАЯ_МОДЕЛЬs()
(например, 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));
Консольный вывод:
Tom - Microsoft Alice - Microsoft Bob - Microsoft
Все остальные операции со связанными зависимыми моделями можно проводить также, как и с обычными моделями.