본문으로 건너뛰기

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: OwnsOneValueConverter 중 어떤 것을 사용해야 하나요?

섹션 제목: “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 통합