본문으로 건너뛰기
ElastiCORE 3.0 은 릴리스 후보(RC)입니다: Maven Central 의 3.0.261022-rc1. 2.2 라인 프로젝트는 2.2 문서를 보세요.
버전: 3.0

엔티티

entity:
EntityName:
meta: entity [@annotations] -- 라벨
fields:
fieldName: fieldType [@annotations] -- 설명
fieldName: fieldType [@annotations] -- 라벨 | 설명
states: ... # 생명주기 (DDD 번들) - 생명주기 문서 참고
commands: ... # 업무 명령 (DDD) - 생명주기 문서 참고

-- 글 은 라벨(@label(글))이 되고, -- 라벨 | 설명 은 라벨과 설명을 함께 줍니다. 라벨은 컬럼 주석과 API 설명이 됩니다.

meta 줄​

어노테이션뜻
@expose(n)REST 컨트롤러 + 서비스 + 검색 DTO. n 은 페이지 크기. 이것만으로 생성·조회·검색·페이지·REST
@service(n)위와 같지만 컨트롤러 없음
@pageable페이징 지원
@root애그리거트 루트 (DDD 번들) - 다른 루트가 목록으로 가진 루트에만 필요
@aggregate(Root)그 루트의 애그리거트 멤버 (보통 추론됨)
@editableDDD 번들: 루트가 평범한 데이터 - 공개 setter, PUT. 없으면 루트는 잠김
@sort(name+)검색이 정렬을 말하지 않을 때의 순서: 속성 + + 오름차순 / - 내림차순, 쉼표로 여러 개 (@sort(orderDate-, orderId-))
@terms(order, purchase, 구매)업무에서 부르는 이름 - Ossie 로 나가는 동의어. 코드에는 영향 없음
@access(...), @owner(필드), @signin누가 무엇을 하는가 - 권한과 로그인
@event(Placed(total), Shipped)루트의 도메인 이벤트 - 파생 값과 이벤트
@expose(20, methods="read,search")컨트롤러가 적은 메서드만 제공 (create, read, search, update, delete). 클라이언트·유스케이스가 따르고 서비스는 모두 둠 - API 와 오류 응답
@restExclude(update, deleteById)methods 로 대체되어 deprecated: 서비스·컨트롤러·유스케이스·TypeScript 클라이언트에서 메서드를 뺌
@table(name) / @schema(name)테이블 이름 / DB 스키마
@Index(name="uk_member_email", columnList="email", unique=true)테이블 인덱스. unique 면 중복이 409
@abstract추상 엔티티 - 상속 전용, 테이블 없음
@extend(Parent)부모의 필드를 상속
@rollup부모 테이블로 컬럼 통합 (단일 테이블 상속)
@embeddable값 객체 - 관계와 값 객체
@auditedHibernate Envers 감사

@sort 는 3.0 규칙 엔진 기능입니다. 2.x 생성기는 읽지 않습니다. 엔티티에 없는 속성을 적으면 DSL 경고 (@sort(...): x is not a field of Product) 후 그 속성만 빠집니다.

예시​

model/entity.yml
entity:
AuditEntity:
meta: entity @abstract
fields:
createdBy: string(20) @updatable(false) @jpa:org.springframework.data.annotation.CreatedBy
createDate: datetime @updatable(false) @jpa:org.springframework.data.annotation.CreatedDate

Product:
meta: entity @root @editable @expose(20) @access(read=public) @sort(name+) -- 상품 (Angelfish, Bulldog ...)
fields:
productId: long @id @sequence
name: string(30)! @search(like)
description: string(3000)!
category: Category @ManyToOne

루트의 규칙 (DDD 번들)​

architecture = 'ddd' 나 'hexagonal' 이 필요합니다.

@invariant(조건, '메시지') - 루트가 항상 참으로 유지하는 것​

Order:
meta: entity @root @expose(30) @invariant(items.size > 0, 'an order has at least one line')

루트에 붙는 OrderInvariants 리스너가 행이 쓰일 때마다(@PrePersist / @PreUpdate) 검사합니다 - 어떤 경로로 저장하든 지나칠 수 없습니다. 어기면 422 입니다. 여러 번 쓸 수 있습니다. 필드 하나에 대한 규칙은 필드에 씁니다 (@min, @minsize) - DDD 번들에서는 그것도 저장 시점에 검사됩니다. @invariant 는 여러 필드를 함께 보는 규칙에 씁니다.

@specification(이름, 조건) - 이름을 가질 만한 도메인 규칙​

Order:
meta: entity @root @specification(highValue, totalAmount > 100) @specification(hasLines, items notEmpty)

OrderSpecifications.highValue() 가 생깁니다 - Predicate<Order> 라서 규칙끼리 조합합니다: highValue().and(hasLines()). 쿼리가 아니라 이미 읽어 온 것에서 고릅니다. ts-model 번들을 쓰면 TypeScript 클라이언트에도 같은 함수가 생깁니다.

@factory(place) - 유효한 애그리거트를 만드는 자리​

OrderFactory.place(...) 가 한 번만 생성되는 틀로 생깁니다. 파라미터는 루트의 필수 필드(생성되는 식별자와 컬렉션 제외)이고, 본문은 직접 쓸 때까지 예외를 던집니다.

조건 문법​

형태뜻
items.size > 0to-many 의 멤버 수
totalAmount > 100숫자 비교 (< 도 가능)
notes notNull필드가 설정되어 있음
items notEmptyto-many 에 무언가 들어 있음

필드·비교·리터럴만 받습니다. >=, <=, == 는 쓸 수 없고(애노테이션 파서가 = 를 키/값 목록으로 읽음), : 도 쓸 수 없습니다(YAML 이 매핑으로 읽음). 읽지 못한 조건은 빠지므로, 생성된 파일에 검사가 있는지 확인하세요.

@behavior - 루트의 메서드만 바꾸는 필드​

나뉜 루트의 필드에 @behavior 를 붙이면 요청으로 받지 않고(READ_ONLY) creation() 에도 없으며, 내 메서드가 protected setter 로 바꿉니다. 루트는 엔티티에 @behavior 를 적지 않아도 XxxBase 와 내 Xxx 로 나뉩니다. 나뉘지 않는 엔티티의 필드 @behavior 는 DSL 경고만 남깁니다 - 거기서는 @readonly 를 씁니다.

잠긴 루트, @editable, creation() 은 DDD에 있습니다.

복합 키​

@id 필드가 여럿이면 KeyDTO 클래스가 생깁니다:

OrderItem:
meta: entity
fields:
orderId: string @id
itemSeq: int @id
quantity: int

피할 이름​

엔티티 이름이 테이블 이름이 되므로 SQL 예약어는 피합니다(Order, User, Group 대신 PurchaseOrder, Member, Team). 필드 이름도 마찬가지입니다(order, group, user, select, from, where, table, index, key, value).