• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

관계가 적용되었을 때 row를 삭제하면 관계가 적용된 row도 삭제 하게 하려면 어떻게 해야 할까요?

22.06.29 21:39 작성 조회수 938

1

  상품 entity와 이미지 entity가 아래 처럼 있다고 가정합니다.

@Entity("products")
export class ProductEntity extends CommonEntity {
  @IsString()
  @IsNotEmpty()
  @Column({ type: "varchar", length: 20, unique: true, nullable: false })
  name: string;

  @IsNumber()
  @IsNotEmpty()
  @Column({ type: "int", unsigned: true, nullable: false })
  price: number;

  @IsString()
  @IsNotEmpty()
  @Column({ type: "varchar", length: 20, nullable: false })
  origin: string;

  @IsString()
  @IsNotEmpty()
  @Column({ type: "varchar", length: 20, nullable: false })
  type: string;

  @IsString()
  @IsNotEmpty()
  @Column({ type: "text", nullable: true })
  description: string;

  @Column({ type: "int", default: 50 })
  quantity: number;

  @Column({ type: "float", default: 0.0 })
  rating: float;

  @OneToOne(() => ImagesEntity, (image) => image.product, { cascade: true })
  @JoinColumn({ name: "imageId" })
  image: ImagesEntity;
}
@Entity("images")
export class ImagesEntity extends CommonEntity {
  @OneToOne(() => ProductEntity, (product: ProductEntity) => product, {
    onDelete: "CASCADE",
    onUpdate: "CASCADE",
  })
  product: ProductEntity;

  @Column({ type: "varchar", nullable: false, unique: true })
  url: string;

  @ManyToOne(() => UserAuthEntity, (Join) => Join.image)
  @JoinColumn({ name: "uploaderId", referencedColumnName: "id" })
  uploader: UserAuthEntity;

  @Column({ type: "enum", enum: ["product upload", "review", "inquiry"] })
  uploadReason: "product upload" | "review";
}

product entity에는 image라는 가상 컬럼이 존재하고 images entity에는 product라는 가상 컬럼이 존재합니다. 여기서 상품쪽 row가 지워지면 이미지쪽 row도 지워지게 하고 싶어서 각각의 가상컬럼에 casecade : true 와 onDelete: "CASCADE"를 주었습니다.

질문 1. 상품 쪽에서 지울 때 이미지 쪽에서도 지워지게 하려면 옵션을 저렇게 설정하는게 맞을까요?

질문 2. 아래는 제가 구글링을 하다가 찾게 된 코드입니다.

const author = await Author.findOne({ id: '123' });
author.books.push(new Book(...));
await author.save();

위 같은 방식이 activate record가 맞을까요?

질문 3. 위 질문이 맞다면 제가 save메서드를 호출해야 cascade가 적용 된다는 글을 봤었는데(https://velog.io/@hahaha/TypeORM-Relation) 그러면 repository pattern을 사용하면 cascade를 적용시킬 수 없는것일까요?

 

답변 1

답변을 작성해보세요.

0

1. cascade가 맞습니다. 다만 코드쪽 말고 실제 DB에도 적용되었는지 워크벤치로 확인해보세요.

2. 네 액티브레코드입니다.

3. cascade는 디비에서 일어나는 일이라서 레포지토리 패턴에서도 됩니다.

이승훈님의 프로필

이승훈

질문자

2022.06.30

products 테이블에서 Foreign Keys 항목에서 Foreign Key Name과 Refrenced Table이 각각 있습니다. 이를 클릭해보면 Foreign Key Options에서 On Update와 On Delete가 각각 RESTRICT로 되어 있었습니다. 이것을 CASCADE 바꾸었더니 문제는 워크밴치에서 적용 후 서버를 껏다 키면 다시 On Update와 On Delete가 RESTRCIT로 재변경 되어 있습니다. nest쪽에서 마이그레이션을 해야할까요?

아뇨 cascade로 바꾼 후 apply까지 누르신 것 맞나요? 그리고 혹시 nest에서 synchronize 옵션 true로 되어있는 것 아닌가요?

이승훈님의 프로필

이승훈

질문자

2022.06.30

아 제가 synchronize를 true로 해놨었네요 감사합니다!

이 경우 엔티티도 수정하셔야 합니다. 엔티티에 cascade 설정이 안 되어있을겁니다.

이승훈님의 프로필

이승훈

질문자

2022.06.30

엔티티에도 수정해야 한다는 말씀은 nestjs에 있는 entity를 말씀하시는건가요?

네 그게 지금 restrict로 되어있어서 자꾸 돌아가는겁니다.

이승훈님의 프로필

이승훈

질문자

2022.06.30

혹시 엔티티에 cascade를 설정하라는 말씀이 image컬럼에 cascade : true가 아닌 Entity 데코레이터에 설정하라는 말씀이신가요?

이승훈님의 프로필

이승훈

질문자

2022.06.30

일단 조현영님께서 cascade로 바꾼후 apply까지 누르고 nest에서 synchronize 옵션 false로 하라 하셔서 바꾼 후 product table을 보면 CASCADE로 설정되어 있기는 합니다.

네 그런데 synchronize: true로 바꾸면 다시 restrict로 돌아가잖아요. 이 말은 지금 엔티티에 restrict(기본값)으로 설정되어 있는 것이에요. synchronize: true더라도 cascade로 유지되어야 합니다.

이승훈님의 프로필

이승훈

질문자

2022.06.30

제가 이미지를 업로드 하고 상품에 image외례키 컬럼을 통해 상품에 이미지를 추가한 후 업로드한 상품을 제거했을 때 relation된 이미지는 테이블에 남아있습니다. 이것이 지금 restrict로 되어 있어서 그렇다는 말씀이시죠?

?? 아까는 워크벤치로 cascade된걸 확인했다고 하신 것 아닌가요? 따라서 같이 안 지워지면 restrict입니다.

https://stackoverflow.com/questions/55098023/typeorm-cascade-option-cascade-ondelete-onupdate

이승훈님의 프로필

이승훈

질문자

2022.06.30

혹시 entity 데코레이터에 synchrnoize : false를 하면 되는것인가요? product entity와 image entity의 entity 데코레이터에 synchrnoize : false 를 하고 typeormconfig에서 synchronize를 true로 해보고 workbench에 product table의 foreignkey 옵션을 보니 cascade로 적용되어있습니다. 

그런데도 해결이 안되네요 ;;

 

아뇨 synchronize는 true인 상태에서도 제대로 되어야 엔티티 설정을 제대로 한 겁니다.

이승훈님의 프로필

이승훈

질문자

2022.07.01

그렇다면 제가 재대로 설정을 안한거같네요 synchronize가 false일 때는 ondelete가 cascade이더니 synchronize를 true로 바꾸니 다시 restrict로 되서요. 혹시 product쪽에서 외례키 컬럼(image)에 cascade: true가 아닌 onDelete : "CASCADE"를 주어야 하나요? 이렇게하고 synchronize까지 true로 하니 워크밴치에서는 현상태가 synchronize가 true임에도 onDelete가 restrict가 아닌 cascade로 되어있어서요. 그리고 조현영님 sleact코드를 봤는데 아무리 봐도 entity데코레이터 쪽에서 restrict를 cascade로 설정하는 부분을 찾을 수가 없었어요. 아마 entity가 디비쪽에서 다 만들어진 테이블을 typeorm generate해서 사용하시는거 같으신데 지우는쪽에서는 onDelete가 "CASCADE"로 되어있고 

@ManyToOne(() => Users, (users) => users.ChannelMembers, {
    onDelete: 'CASCADE',
    onUpdate: 'CASCADE',
  })
  @JoinColumn([{ name: 'UserId', referencedColumnName: 'id' }])
  User: Users;

지워짐을 당하는쪽에서는 cascade 관련 옵션이 없어요.

@OneToMany(
    () => WorkspaceMembers,
    (workspacemembers) => workspacemembers.User,
  )
  WorkspaceMembers: WorkspaceMembers[];

엔티티쪽 옵션을 봐도 스키마와 이름밖에 보이지 않았어요.

@Entity({ schema: 'sleact', name: 'channelmembers' })

지우는 쪽에서보면 조인 컬럼이 있는데 이는 지워지는쪽의 외례키를 갖고 있는것으로 보이고 제가 처음 질문을 올렸을 때는 상품 쪽에서 지우는데 imagesEntity 의외례키 컬럼을 갖는 image에는 

  @OneToOne(() => ImagesEntity, (image) => image.product, { cascade: true })
  @JoinColumn({ name: "imageId" })
  image: ImagesEntity;

위 처럼 되어 있었는데 혹시 제 경우는 OneToOne이라 cascade를 저렇게 둔거고 조현영님께서의 경우는 ManyToOne이라 저렇게 하신건가요? 제 생각에는 image컬럼을 아래 처럼 두어야 된다고 생각하기는해요.

  @OneToOne(() => ImagesEntity, (image) => image.product, { onDelete: "CASCADE" })
  @JoinColumn({ name: "imageId" })
  image: ImagesEntity;

 

OneToMany에서는 onDelete같은 옵션이 없을겁니다. OneToOne에서는 있을갑니다. 제가 위에 스택오버플로우도 첨부해드렸습니다.

이승훈님의 프로필

이승훈

질문자

2022.07.01

 이 부분에 대해서는 일단 보류해두고 제가 나중에 구글링으로 알아볼게요 끝까지 알려주셔서 감사합니다 :)