모던 ABAP을 이야기할 때 CDS(Core Data Services)를 빼놓을 수 없다. S/4HANA의 데이터 모델, OData 서비스, Fiori 화면, 그리고 [RAP](/education/abap-rap-introduction)까지 전부 CDS 위에 서 있기 때문이다. CDS를 모르면 모던 ABAP의 절반은 못 읽는 셈이다. CDS는 **데이터 모델을 데이터베이스 가까이로 끌어내린 것**이다. 옛날처럼 ABAP 프로그램에서 데이터를 긁어 가공하는 게 아니라, 모델 자체를 HANA로 푸시다운(push-down)해서 DB가 무거운 일을 하게 한다. 이게 HANA 시대의 **'Code-to-Data'** 패러다임 — 데이터를 애플리케이션 서버로 끌어올려 처리하는 대신, 처리 로직을 데이터가 있는 DB 쪽으로 내리는 발상이다. 거기에 어노테이션(annotation)으로 의미를 입히고, 어소시에이션(association)으로 관계를 엮는다. 이 글은 CDS의 핵심 개념을 처음부터 정리한다. ## 1. SE11 뷰랑 뭐가 다른가 ECC 시절의 `SE11` 데이터베이스 뷰도 여러 테이블을 조인해 보여줬다. 그런데 그건 딱 거기까지였다 — 조인된 결과를 읽는 것 이상은 못 했다. CDS 뷰는 거기에 세 가지를 더한다. - **어노테이션**: 이 필드는 통화다, 이건 UI에서 이렇게 보여라, 이 뷰는 OData로 노출해라 — 같은 의미(semantic)를 모델에 직접 박는다. - **어소시에이션**: 조인을 미리 다 하지 않고 "관계만 정의"해 뒀다가, 실제로 그 경로를 쓸 때만 조인한다. - **계층 구조**: 뷰가 뷰를 쌓아 올려, 표준화된 데이터 모델(VDM)을 만든다. 즉 CDS는 "조인된 테이블"이 아니라 **의미가 입혀진, 재사용 가능한 데이터 모델**이다. ## 2. 세 가지 CDS — 진화의 역사 CDS를 처음 보면 헷갈리는 게, 종류가 셋이라는 점이다. 진화 순서대로 보면 정리된다. | 종류 | 정의문 | 특징 | |---|---|---| | DDIC 기반 뷰 (옛것) | `DEFINE VIEW` | `@AbapCatalog.sqlViewName` 필수, 활성화 시 객체 2개(CDS+DDIC뷰) 생성. 지원되나 더 개발 안 됨 | | **뷰 엔티티 (현행 권장)** | `DEFINE VIEW ENTITY` | 7.55+. 이름 하나, 객체 1개. `sqlViewName` 불필요. 활성화 빠르고 문법 검사 엄격 | | 프로젝션 뷰 | `DEFINE VIEW ENTITY ... AS PROJECTION ON` | RAP의 투영(projection) 계층 전용. 기존 뷰를 특정 서비스용으로 잘라 노출 | 핵심 한 줄: **새로 만들 땐 무조건 `DEFINE VIEW ENTITY`(뷰 엔티티)다.** 옛 DDIC 기반 뷰는 호환을 위해 남아 있을 뿐, 신규 개발에 쓸 이유가 없다. 가장 큰 차이가 별도 DDIC 뷰를 안 만든다는 것 — 그래서 `sqlViewName` 어노테이션이 사라졌고 활성화도 빨라졌다. ## 3. 기본 문법 — Before / After 옛 DDIC 기반 뷰와 새 뷰 엔티티를 나란히 보면 차이가 한눈에 들어온다. ```abap " 옛 방식 — DDIC 기반 뷰 (객체 2개, sqlViewName 필요) @AbapCatalog.sqlViewName: 'ZIBOOKV' @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: '도서 기본 뷰' define view ZI_Book as select from zbook { key book_id, title, author_id } " 신문법 (7.55+) — 뷰 엔티티 (객체 1개, sqlViewName 없음) @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: '도서 기본 뷰' define view entity ZI_Book as select from zbook { key book_id, title, author_id } ``` 뷰 엔티티는 `@AbapCatalog.sqlViewName` 한 줄이 사라졌고, 내부적으로 만드는 객체도 하나뿐이다. 작성은 SE11이 아니라 **ADT(Eclipse)**에서 한다. ## 4. 어노테이션 — 데이터에 의미를 입힌다 CDS가 단순한 뷰를 넘어서는 이유가 어노테이션이다. 필드와 뷰에 의미를 박아두면, 그걸 OData·Fiori·분석 프레임워크가 알아서 읽어간다. | 어노테이션 | 역할 | |---|---| | `@EndUserText.label` | 화면에 보일 레이블 | | `@AccessControl.authorizationCheck` | 접근 제어 여부(아래 6번) | | `@OData.publish: true` | 이 뷰를 OData 서비스로 바로 노출 | | `@UI.*` | Fiori Elements 화면 구성(어느 필드를 어디에) | | `@Analytics.*` | 분석용 쿼리/큐브로 분류 | | `@Semantics.*` | 금액·통화·수량 등 의미 부여 | | `@VDM.viewType` | VDM 계층 분류(아래 7번) | 어노테이션은 `@`로 시작하고, 뷰 전체에 붙이거나(헤더) 개별 필드에 붙인다. "데이터를 정의하면서 동시에 그 데이터의 쓰임새까지 선언한다"가 CDS 설계 철학이다. ## 5. 어소시에이션 — 필요할 때만 조인 어소시에이션은 CDS 데이터 모델의 핵심이다. 조인을 미리 다 걸어두는 대신 **관계만 정의**해 두고, 실제로 그 경로를 참조할 때만 조인이 일어난다. ```abap define view entity ZI_Book as select from zbook association [0..1] to ZI_Author as _Author on $projection.author_id = _Author.author_id { key book_id, title, author_id, _Author.name as author_name, // 경로를 쓰면 그때 조인 _Author // 어소시에이션 자체를 노출(소비뷰에서 펼침) } ``` `[0..1]`은 카디널리티(이 도서당 저자 0~1명)다. `author_name`처럼 경로를 실제로 쓰면 조인이 걸리고, 안 쓰면 안 걸린다. 그래서 무거운 조인을 미리 다 거는 SE11 뷰보다 효율적이다. `_Author`를 그대로 노출해 두면 상위 소비 뷰나 OData에서 펼쳐 쓸 수 있다. ## 6. 접근 제어 — DCL 뷰 정의(DDL)와 **권한(DCL, Data Control Language)을 분리**하는 것도 CDS의 특징이다. 뷰는 "무엇을 보여줄지", DCL은 "누가 어느 행을 볼 수 있는지"를 따로 정의한다. ```abap @AccessControl.authorizationCheck: #CHECK define view entity ZI_Book as select from zbook { ... } " 별도 DCL 파일 — 행 단위 권한 define role ZI_Book_Role { grant select on ZI_Book where (author_id) = aspect pfcg_auth( ... ); } ``` `@AccessControl.authorizationCheck`를 `#CHECK`로 두고 `DEFINE ROLE`로 권한 규칙을 주면, ABAP SQL로 이 뷰를 읽을 때 권한이 자동 적용된다. 처음 만들 땐 `#NOT_REQUIRED`로 시작하고, 권한이 필요해지면 나중에 역할을 붙이는 게 권장 흐름이다. ## 7. VDM — 뷰를 계층으로 쌓는다 SAP 표준 CDS는 아무렇게나 만든 게 아니라 **VDM(Virtual Data Model)**이라는 계층 구조를 따른다. - **Basic interface 뷰**: 테이블에 가장 가까운 1차 가공 - **Composite interface 뷰**: Basic 뷰들을 엮은 중간 계층 - **Consumption 뷰**: 특정 앱/화면을 위한 최종 소비층 `@VDM.viewType`으로 각 뷰가 어느 계층인지 표시한다. 직접 모델을 설계할 때도 이 계층을 흉내 내면, 재사용성과 유지보수가 확 좋아진다. "테이블 → Basic → Composite → Consumption"으로 내려오는 흐름을 잡는 게 CDS 모델링의 기본기다. ## 8. 소비 — OData·Fiori·RAP로 나가는 길 CDS 뷰는 만들어두면 여러 방향으로 소비된다. - **간단 노출(레거시)**: `@OData.publish: true`를 붙이면 그 뷰가 OData 서비스로 바로 나간다(auto-exposure). 빠르지만 이 방식은 **구식이라 최신 S/4HANA·BTP에서는 권장되지 않는다**(deprecated). 옛 코드에서 자주 보이니 알아만 두자. - **RAP (표준)**: 신규 OData 서비스는 읽기 전용이라도 RAP으로 가는 게 표준이다. **프로젝션 뷰**(`AS PROJECTION ON`)가 투영 계층을 맡고, 서비스 정의(service definition)와 바인딩(service binding)으로 OData V2/V4를 게시한다. 즉 CDS는 그 자체가 끝이 아니라 **RAP·Fiori·분석으로 가는 토대**다. 여기서 익힌 뷰 엔티티·어소시에이션·어노테이션이 [RAP](/education/abap-rap-introduction)에서 그대로 다시 등장한다. ## 9. 어디서부터 시작할까 - 작성 도구는 **ADT(Eclipse)**다. SE11이 아니다. - 신규는 무조건 `DEFINE VIEW ENTITY`로 시작한다. - 조인을 미리 다 걸지 말고 **어소시에이션**으로 풀어라 — 성능과 재사용성이 같이 좋아진다. - 권한은 처음엔 `#NOT_REQUIRED`, 필요해지면 DCL 추가. - 표준 SAP CDS(`I_*` 인터페이스 뷰)를 검색해 재료로 가져다 쓰면 바닥부터 안 짜도