시퀄라이즈 belongsToMany 외래키 조합 중복 방지 문제

나른한 개발자·2022년 4월 21일
0

node & sequelize

목록 보기
1/2

프로젝트 중 궁금한게 있어 데이터 베이스에 데이터를 추가하려다가 다음과 같은 에러가 생겼다.

original: error: duplicate key value violates unique constraint "products_options_product_id_option_id_key"
8:08
detail: ‘Key (product_id, option_id)=(1, 1) already exists.’

문제가 발생한 테이블 관계에 대해 간략히 설명하자면 products 테이블과 options 테이블이 다대다로 관계를 맺고 있고 그 중간 테이블이 products_options 이다.

시퀄라이즈로 작성한 모델은 아래와 같고 associatebelongsToMany로 다대다 관계를 설정해주었다.

class Product extends Sequelize.Model {
  static init(sequelize) {
    return super.init(
      {
// --- 중간 생략 ---
      },
    );
  }
  static associate(db) {
    db.Product.belongsToMany(db.Option, { through: db.ProductOption });
  }
}

class Option extends Sequelize.Model {
  static init(sequelize) {
    return super.init(

// --- 중간 생략 ---
    );
  }
  static associate(db) {
    db.Option.belongsToMany(db.Product, { through: db.ProductOption });
  }
}

class ProductOption extends Sequelize.Model {
  static init(sequelize) {
    return super.init(
      {
        productId: {
          type: Sequelize.INTEGER,
          references: {
            model: 'products',
            key: 'id',
          },
          allowNull: false,
        },
        optionId: {
          type: Sequelize.INTEGER,
          references: {
            model: 'options',
            key: 'id',
          },
          allowNull: false,
        },
      },
// --- 중간 생략 ---
    );
  }
  }
}

데이터베이스에 테이블 생성 후 \d products_options 로 description을 보면 index부분에 아래와 같이 뜬다.

“products_options_product_id_option_id_key” UNIQUE CONSTRAINT ...

(product_id, option_id) 키 조합이 중복 될 수 없다는 내용인 것 같다. 즉, (1, 1) 키 조합이 이미 존재할 때 또 다시 (1,1)은 넣을 수 없다는 것이다. 하지만 해당 테이블은 soft delete가 적용된 테이블이었고..저 테이블 이외에도 주문과 관련된 중간 테이블은 사용자가 같은 상품을 또 주문할 수도 있기 때문에 이러한 제약조건이 생긴다는 것이 이해가 되지 않았다.

중복을 허용하기 위해 products_options 테이블에 각각의 외래키에 unique: true 속성도 줘봤지만 문제는 해결되지 않았다. 아마 belongsToMany 가 관계를 설정하면서 부여되는 속성인 것 같았다.

제약 조건을 없애기 위해 belongsToMany를 다 지운 후 다시 마이그레이트를 해보았더니 위의 unique constraint 가 생기지 않았고 중복된 외래키 쌍을 추가 할 수 있었다.

위의 제약조건의 의미는 무엇일까? 구글링을 해봐도 관련 내용은 없는 것 같아서 혹시 같은 고민을 가진 분들을 위해 포스팅을 해보았다.

+) belongsToMany를 지울 경우에는 일대다 관계를 hasMany, belongsTo로 설정해줘야한다! 그래야 Eager loading을 할 수 있다. 컬럼에만 references를 적어주는거로는 안됨.

profile
Start fast to fail fast

0개의 댓글