목차

🚀 TypeORM 순환 참조(Circular Dependency) 문제 해결하기

📚 1. 순환 참조(Circular Dependency)란?

문제 상황 예시

에러 메시지

🛠️ 2. 순환 참조의 원인

✅ 3. 해결 방법

방법 1: Lazy Resolver 사용하기

방법 2: Import 순환 참조 해결

방법 3: Enum 타입 사용 문제 해결

🧠 4. 순환 참조를 피하기 위한 권장 사항

📊 5. 비교 요약

🚀 6. 마무리

태그

#NESTJS

#NEST

#TYPESCRIPT

#LIBRARY

#TYPEORM

[Nest] Error: A circular dependency has been detected

2025년 1월 2일 15:28

66-thumbnail-image

🚀 TypeORM 순환 참조(Circular Dependency) 문제 해결하기

TypeORM을 사용할 때 발생할 수 있는 대표적인 문제 중 하나가 순환 참조(Circular Dependency) 입니다. 이 글에서는 해당 문제가 왜 발생하는지, 어떻게 해결할 수 있는지, 그리고 enum 타입에서도 같은 문제가 발생할 수 있는 이유에 대해 정리합니다.


📚 1. 순환 참조(Circular Dependency)란?

순환 참조란?
두 엔터티가 서로를 참조할 때 발생합니다. 예를 들어 OrderShippingLocation 엔터티가 서로를 참조하게 될 경우, TypeORM은 이를 어떻게 해결해야 할지 알 수 없어 에러를 발생시킵니다.

문제 상황 예시

Order 엔터티

import { Entity, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { ShippingLocation } from './shipping-location.entity';

@Entity()
export class Order {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(() => ShippingLocation, (location) => location.orders)
  shippingLocation: ShippingLocation;
}

ShippingLocation Entity

import { Entity, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Order } from './order.entity';

@Entity()
export class ShippingLocation {
  @PrimaryGeneratedColumn()
  id: number;

  @OneToMany(() => Order, (order) => order.shippingLocation)
  orders: Order[];
}

에러 메시지

Error: A circular dependency has been detected (property key: "shippingLocation").
Please, make sure that each side of a bidirectional relationship are using lazy resolvers ("type: () => ClassType").

🛠️ 2. 순환 참조의 원인

  • TypeScript의 메타데이터 리플렉션: TypeORM은 TypeScript의 리플렉션(reflect-metadata)을 사용하여 타입을 분석합니다.
  • 동일한 파일 로딩 타이밍: 엔터티가 서로를 참조할 때, 어느 한쪽이 완전히 정의되기 전에 다른 한쪽이 이를 참조하려고 시도하면서 문제가 발생합니다.
  • 열거형(Enum) 타입 문제: typeenum을 직접 사용하면 TypeORM이 해당 enum의 타입을 즉시 확인하려고 하여 문제가 발생할 수 있습니다.

✅ 3. 해결 방법

방법 1: Lazy Resolver 사용하기

type 속성에 직접 클래스를 지정하지 말고, 람다 함수(() => ClassType) 를 사용해 TypeORM이 참조를 지연하도록 합니다.

Order 엔터티 수정

import { Entity, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { ShippingLocation } from './shipping-location.entity';

@Entity()
export class Order {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(() => ShippingLocation, (location) => location.orders)
  shippingLocation: ShippingLocation;
}

ShippingLocation 엔터티 수정

import { Entity, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Order } from './order.entity';

@Entity()
export class ShippingLocation {
  @PrimaryGeneratedColumn()
  id: number;

  @OneToMany(() => Order, (order) => order.shippingLocation)
  orders: Order[];
}

📝 핵심 포인트:

  • type() => ShippingLocation와 같은 람다 표현식을 사용해 TypeORM이 지연 로딩하도록 합니다.

방법 2: Import 순환 참조 해결

경우에 따라 import 순서 가 원인일 수도 있습니다. 아래와 같이 import를 변경해보세요.

Order 엔터티 수정

import { Entity, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';

@Entity()
export class Order {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(() => import('./shipping-location.entity').then(m => m.ShippingLocation), (location) => location.orders)
  shippingLocation: ShippingLocation;
}
  • import() 동적 임포트를 사용하여 런타임에 참조가 설정되도록 만듭니다.

방법 3: Enum 타입 사용 문제 해결

enum 타입을 type에 직접 사용하면 순환 참조와 유사한 문제가 발생할 수 있습니다. type 속성 대신 () =>를 사용해 명확하게 정의합니다.

잘못된 예시

@Column({
  type: 'enum',
  enum: MyEnum,
})
status: MyEnum;

올바른 예시

@Column({
  type: 'enum',
  enum: () => MyEnum,
})
status: MyEnum;

📝 핵심 포인트:

  • typeenum을 직접 사용하지 말고 람다 표현식으로 감싸서 사용하세요.

🧠 4. 순환 참조를 피하기 위한 권장 사항

  1. Lazy Resolver(() => ClassType) 를 사용하여 참조를 지연합니다.
  2. import() 동적 임포트를 사용하여 순환 참조를 피합니다.
  3. enum을 사용할 때는 () => MyEnum과 같은 방식으로 참조합니다.
  4. 가능한 경우, 양방향 관계를 단방향 관계로 바꾸는 것도 고려해보세요.
  5. 리팩토링을 통해 공통된 부분을 별도의 중간 테이블로 분리할 수도 있습니다.

📊 5. 비교 요약

문제 원인해결 방법예시
양방향 관계Lazy Resolver 사용() => ClassType
import 순환 참조동적 import 사용import('./entity').then(m => m.Class)
Enum 타입Lazy Resolver 사용enum: () => MyEnum
복잡한 의존성중간 엔터티로 분리JoinTable 등 사용

🚀 6. 마무리

  • 순환 참조는 TypeORM에서 흔히 발생할 수 있는 문제입니다.
  • 올바른 type 설정과 Lazy Resolver 사용은 대부분의 문제를 해결할 수 있습니다.
  • enum 타입에서도 같은 원인이 발생할 수 있으므로 주의해야 합니다.

이제 TypeORM 순환 참조 문제를 이해하고 해결할 수 있을 것입니다. 여러분의 프로젝트에 맞는 해결 방법을 선택하여 안정적인 관계를 설계하세요! 🚀✨

🔗 참고 링크: