프로젝트 중 궁금한게 있어 데이터 베이스에 데이터를 추가하려다가 다음과 같은 에러가 생겼다.
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 이다.
시퀄라이즈로 작성한 모델은 아래와 같고 associate
에 belongsToMany
로 다대다 관계를 설정해주었다.
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를 적어주는거로는 안됨.