본문으로 건너뛰기

ORM 통합 패턴

Entity Framework Core와 값 객체를 통합하는 패턴을 학습합니다. OwnsOne, OwnsMany, Value Converter 패턴을 다룹니다.


  • EF Core의 OwnsOne 패턴으로 값 객체 매핑
  • OwnsMany 패턴으로 컬렉션 값 객체 매핑
  • ValueConverter를 사용한 단순 변환
  • 값 객체의 데이터베이스 저장/로드

Terminal window
cd Docs/tutorials/Functional-ValueObject/04-practical-guide/02-ORM-Integration/OrmIntegration
dotnet run

=== ORM 통합 패턴 ===
1. OwnsOne 패턴 - 복합 값 객체 매핑
────────────────────────────────────────
저장된 사용자: 홍길동
이메일: hong@example.com
주소: 서울 강남구 테헤란로 123 (06234)
2. Value Converter 패턴 - 단일 값 객체 변환
────────────────────────────────────────
상품 코드: EL-001234
가격: 50,000 KRW
3. OwnsMany 패턴 - 컬렉션 값 객체 매핑
────────────────────────────────────────
주문자: 김철수
주문 항목:
- 상품 A: 2개 x 10,000원
- 상품 B: 1개 x 25,000원

modelBuilder.Entity<User>()
.OwnsOne(u => u.Address, address =>
{
address.Property(a => a.City).HasColumnName("City");
address.Property(a => a.Street).HasColumnName("Street");
address.Property(a => a.PostalCode).HasColumnName("PostalCode");
});

테이블 구조:

Users
├── Id (PK)
├── Name
├── Email ← OwnsOne (단일 컬럼)
├── City ← OwnsOne Address
├── Street ← OwnsOne Address
└── PostalCode ← OwnsOne Address
modelBuilder.Entity<Product>()
.Property(p => p.Code)
.HasConversion(
code => code.Value, // 저장 시
value => ProductCode.CreateFromValidated(value) // 로드 시
);
modelBuilder.Entity<Order>()
.OwnsMany(o => o.LineItems, lineItem =>
{
lineItem.Property(l => l.ProductName);
lineItem.Property(l => l.Quantity);
lineItem.Property(l => l.UnitPrice);
});

테이블 구조:

Orders OrderLineItems
├── Id (PK) ├── OrderId (FK)
└── CustomerName ├── ProductName
├── Quantity
└── UnitPrice

패턴사용 시기장점단점
OwnsOne복합 값 객체같은 테이블에 저장컬럼 수 증가
OwnsMany컬렉션 값 객체정규화된 구조별도 테이블 필요
ValueConverter단일 값 객체간단한 변환복합 타입 불가

Q1: OwnsOne과 ValueConverter 중 어떤 것을 사용해야 하나요?

섹션 제목: “Q1: OwnsOne과 ValueConverter 중 어떤 것을 사용해야 하나요?”

A: 단일 값을 가진 값 객체(Email, ProductCode 등)에는 ValueConverter가 간단합니다. 여러 속성으로 구성된 복합 값 객체(Address, Money 등)에는 OwnsOne을 사용하여 각 속성을 별도 컬럼에 매핑합니다.

Q2: ValueConverter에서 로드 시 CreateFromValidated를 사용하는 이유는 무엇인가요?

섹션 제목: “Q2: ValueConverter에서 로드 시 CreateFromValidated를 사용하는 이유는 무엇인가요?”

A: 데이터베이스에 저장된 값은 이미 검증을 통과한 값이므로, 다시 검증할 필요가 없습니다. Create 메서드를 사용하면 불필요한 검증 비용이 발생하고 Fin<T> 언래핑도 필요합니다. CreateFromValidated는 검증을 건너뛰고 바로 인스턴스를 생성합니다.

Q3: OwnsMany를 사용하면 별도 테이블이 생기는데, 성능 문제는 없나요?

섹션 제목: “Q3: OwnsMany를 사용하면 별도 테이블이 생기는데, 성능 문제는 없나요?”

A: JOIN이 필요하므로 단일 테이블보다 조회 성능이 약간 떨어질 수 있습니다. 하지만 EF Core가 자동으로 관계를 관리해주고, 컬렉션 크기가 크지 않다면 실무에서 문제가 되는 경우는 드뭅니다. 성능이 중요한 조회에는 별도의 읽기 모델을 사용하는 것이 일반적입니다.


CQRS 통합 패턴을 학습합니다.

→ 4.3 CQRS 통합