TypeORM에서 Soft Delete 구현

jegw·2023년 8월 10일
2

TIL

목록 보기
59/77
post-custom-banner

Soft Delete는 논리 삭제라고도 부른다.
실제 DB에서의 작업은 update와 같다. 삭제 여부를 저장하는 컬럼을 업데이트하는 것이다.

Typeorm으로는 @DeletedDateColumn() 데코레이터를 써서 soft delete를 구현할 수 있다.

soft delete

  1. 엔티티에 deleted_at 컬럼을 만든다.
import {
  Column,
  CreateDateColumn,
  DeleteDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  username: string;

  @Column()
  password: string;

  @CreateDateColumn({ type: 'timestamp' })
  create_at: Date;

  @UpdateDateColumn({ type: 'timestamp' })
  update_at: Date;
  
  // null이 디폴트로 저장된다.
  @DeleteDateColumn()
  deletedAt: Date | null;
}
  1. 서비스에서 softDelete메소드를 사용한다.
import { Repository } from 'typeorm';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private userRepository: Repository<User>,
  ) {}

  async softDeleteUser(id: number) {
    const existingUser: User = await this.userRepository.findOne({
      where: { id },
      relations: ['boards'],
    });

    if (!existingUser) {
      throw new NotFoundException('id와 일치하는 유저가 없습니다.');
    }
    try {
      await this.userRepository.softDelete(id); 📌
      return { message: '회원탈퇴를 완료했습니다.' };
    } catch (error) {
      throw new HttpException('서버 에러', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}

softDelete메소드가 정상 작동하면 deleted_at 컬럼에 삭제를 한 날짜가 저장된다.

조회 시

  • find, findOne메소드는 soft-delete된 데이터는 제외하고 조회한다.

soft-delete된 행도 조회하고 싶다면 withDeleted:true 옵션을 사용한다.

const users = await userRepository.find({
  withDeleted: true,
});

const userWithDeleted = await userRepository.findOne(id, {
  withDeleted: true,
});

soft-delete된 데이터만 조회 시

const softDeletedUsers = await userRepository
  .createQueryBuilder('user')
  .where('user.deletedAt IS NOT NULL')
  .getMany();

복원 방법

  • deleted_at 컬럼을 null로 바꿔준다.
// 일단, soft-delete된 행을 조회합니다.
const softDeletedUser = await userRepository.findOne(id, {
  withDeleted: true,
});

if (softDeletedUser) {
  // deletedAt 속성을 null로 설정하여 복원합니다.
  softDeletedUser.deletedAt = null;
  // 변경된 속성을 저장합니다.
  await userRepository.save(softDeletedUser);
}

SQL을 이용하여 복원하는 방법

update user set deleted_at = null
where id in (select id from user where deleted_at is not null)

이런식으로 하면 이런 에러를 만난다.

Error: ER_UPDATE_TABLE_USED: You can't specify target table 'user' for update in FROM clause

MySQL에서는 한 번에 하나의 테이블만 업데이트하거나 다른 테이블을 참조할 수 있기 때문에 이런 에러가 발생한다.

  • 서브쿼리를 join하여 해결한다.
UPDATE user 
	JOIN (SELECT id FROM user  
    	  WHERE deleted_at IS NOT NULL) AS deleted_user
    ON user.id = deleted_user.id
SET user.deleted_at = NULL;
   
post-custom-banner

0개의 댓글