Связь один-ко-многим

Последнее обновление: 24.11.2023

Например, в одной компании может работать несколько человек. То есть мы имеем отношение одни-ко-многим (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

Все остальные операции со связанными зависимыми моделями можно проводить также, как и с обычными моделями.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850