Как я могу обновить некоторую сущность с отношением ManyToMany

#javascript #postgresql #nestjs #typeorm

Вопрос:

помогите мне, пожалуйста. Я действительно не понимаю, как это работает, у меня есть сущность под названием Product, имеющая множество связей с другой сущностью под названием Car с включенным флагом true.

 @Entity()
export class Product {
  @PrimaryGeneratedColumn()
  id: number

  @ManyToMany(() => Car, { cascade: true })
  @JoinTable()
  cars: Car[]
}
 

Сущность автомобиля не содержит ссылки на сущность продукта. Это означает, как я думаю, что отношение однонаправленное.
Поэтому, когда я сохраняю продукт, я устанавливаю машины для этого продукта:

 const cars = await this.carService.getByIds(createProductDto.cars)

const newProduct = this.productsRepository.create({
    ...createProductDto,
    cars
})

await this.productsRepository.save(newProduct)
 

Я получаю объекты автомобилей по идентификаторам и сохраняю их в продукте. Это хорошо работает. Я не уверен, что это лучший способ, но другого я не знаю.

Проблемы возникают, когда я пытаюсь обновить какой-либо существующий продукт в базе данных. Я получаю ошибки при выпадении:

 ERROR [ExceptionsHandler] duplicate key value violates unique constraint "PK_f7b49d8fd8d09ea2fc2e7542f3f"
 

или

 Error: Cannot query across many-to-many for property cars
 

или что-то другое…
Помогите мне, пожалуйста. Я хочу понять, как лучше всего работать с такими отношениями. Каков наилучший способ его создания, обновления и удаления?
Спасибо

Ответ №1:

Вы утверждаете, что у вас есть М:М между автомобилями и продуктами, но это не то, что вы описываете. Вы описываете 1:M для автомобилей и продуктов. Ссылка на автомобили в таблице «Продукты» означает, что в данном автомобиле может быть много Продуктов, но данный продукт может использоваться только 1 автомобилем. Это результат ссылки на автомобили из продуктов (я бы не классифицировал их как однонаправленные, поскольку, учитывая, что я могу получить один из них, другой, это просто число, которое я могу получить, меняется). Тем не менее, я верю, что вы хотите M:M. Типичная реализация для M:M требует 3-й таблицы. При такой конфигурации ни таблица автомобилей, ни таблица продуктов не ссылаются друг на друга, вместо этого третья таблица ссылается на обе. К сожалению, я не знаю или не узнаю вашего менеджера запутывания (ORM, который вы используете). Поэтому я набросаю возможное определение ddl для таблиц.

 create table cars ( car_id   integer generated always as identity primary key
                  , vin      text 
                  , manufacturer text
                  -- other Car attributes
                  );
                 
create table products( prod_id integer generated always as identity primary key
                     , manufacturer text 
                     -- other product 
                     ); 
                     
-- create the reference/intersection table for M:M Cars:Products
create table car_products( car_id    
                         , prod_id   
                         -- attributes that pertain only to the combination of 
                         -- of the other tables 
                         , model_code text 
                         , serial_number text
                         -- constraints  
                         , constraint car_products_pk
                                      primary key (car_id, prod_id)
                         , constraint car_products_2_cars_fk
                                      foreign key (car_id) 
                                      references cars(car_id) 
                                      on delete cascade
                         , constatint car_products_2_products_fk
                                      foreign key(prod_id)
                                      references products(prod_id) 
                                      on delete cascade                                      
                         ); 
 

Теперь с помощью этой настройки данный автомобиль может иметь любое количество продуктов, и данный продукт может использоваться любым количеством автомобилей. (Примечание: В этой настройке продукт отличается от детали.) Я надеюсь, что это поможет вам понять отношения 1:M против отношений M:M.

Комментарии:

1. Одна деталь может быть применена к нескольким автомобилям. Например, эта деталь представляет собой двигатель под названием LY7 (двигатель GM объемом 3,6 л). Этот двигатель может быть применен к: Cadillac CTS, Cadillac STS, Cadillac SRX, Holden Commodore, Buick Park Avenue, Buick LaCrosse, Suzuki XL7 и Pontiac G8. Я имею в виду, что мне нужно много-много отношений. Также я использую typeorm ORM, и в документации говорится, что третья таблица будет создана автоматически: typeorm.io/#/many-to-many-relations/. … И это работает, потому что в postgresql была создана таблица product_cars_car