Mapping 절이 필요한 이유 — DB 컬럼명과 CDS 필드명 불일치 문제
SAP RAP(RESTful Application Programming Model)에서 비즈니스 오브젝트를 설계하다 보면, 데이터베이스 테이블의 컬럼명이 짧고 함축적인 이름(예: MANDT, SOITEM_ID, NETWR)으로 작성되어 있는 반면, CDS 뷰는 가독성 높은 의미 기반 필드명(예: SalesOrderItemId, NetAmount)으로 노출되는 상황을 자주 만나게 됩니다. 이 글에서는 BDEF의 mapping for 절을 활용해 두 이름 공간을 안전하게 연결하는 방법을 단계별로 다룹니다.
- DB 테이블 컬럼명과 CDS Projection 필드명이 다를 때 매핑하는 방법 이해
- Managed 시나리오에서
mapping for ... corresponding문법 습득 - EML
MODIFY/READ호출 시 필드 참조 규칙 파악 - Late Numbering, Draft 활성화 시 매핑 주의사항 점검
- 현업에서 자주 발생하는 매핑 오류 진단 및 대응 전략 수립
이 글을 읽기 전에 알아두면 좋은 내용
ABAP CDS View와 CDS Projection View의 차이, RAP의 Managed/Unmanaged 시나리오 구분, BDEF(Behavior Definition) 기본 문법, EML(Entity Manipulation Language)의 MODIFY ENTITIES 구문에 대한 기초적인 이해가 필요합니다. ABAP RESTful Programming Model 입문 과정을 한 번이라도 수행한 경험이 있으면 본문 내용을 따라가기 수월합니다.
환경 및 버전 정보
본 예제는 다음 환경을 기준으로 작성되었습니다. 버전이나 에디션에 따라 일부 문법이나 동작이 다를 수 있으므로, 실제 적용 시 시스템 릴리스를 반드시 확인해야 합니다.
- SAP S/4HANA Cloud Private Edition 2023 또는 SAP BTP ABAP Environment(스팁) 2024 이상
- ABAP Development Tools(ADT) for Eclipse 3.38 이상 권장
- ABAP Language Version: ABAP for Cloud Development
- RAP Managed Scenario, Draft 옵션 비활성/활성 양쪽 시나리오 모두 포함
- 예제 데이터베이스 테이블 명명 규칙은 Z 네임스페이스를 기준으로 표기
일반적으로 ABAP for Cloud Development 환경에서는 클라우드 검증 규칙이 더 엄격하게 적용되므로, On-Premise 환경에서 동작하던 코드가 그대로 동작하지 않을 수 있습니다.
매핑 절의 핵심 동작 원리
RAP는 OData/REST를 통해 들어온 요청 페이로드를 CDS Projection 필드명을 기준으로 받아들입니다. 하지만 실제 INSERT/UPDATE/DELETE는 데이터베이스 테이블에 대해 수행되어야 하며, 이때 프레임워크는 "외부 이름(CDS Field)"을 "내부 이름(DB Column)"으로 변환해야 합니다. 이 변환을 명시적으로 알려주는 장치가 바로 BDEF의 mapping for 절입니다.
비유하자면 mapping for 절은 공항 출입국 카운터의 통역사 역할에 가깝습니다. 외국에서 도착한 승객(OData 페이로드)이 자기 나라 언어(CDS 필드명)로 정보를 전달하면, 통역사는 그 정보를 공항 내부 시스템(DB 컬럼명)이 이해할 수 있는 형태로 바꿔 전달합니다. 통역사가 없다면 프레임워크는 필드명이 일치하지 않는다는 이유로 요청을 거부합니다.
매핑이 필요한 대표적인 케이스는 다음과 같습니다.
- 레거시 테이블을 재사용해야 하지만 필드명이 단축어로 되어 있는 경우
- 여러 CDS Projection 레이어에서 비즈니스 의미 기반 명칭을 부여한 경우
- 다국어 환경에서 표준 영문 비즈니스 명칭으로 통일이 요구되는 경우
- Key 필드 이름을
UUID같은 기술 명칭이 아닌 도메인 명칭으로 노출하고 싶은 경우
CDS View 단계에서 AS 별칭을 부여하면 외부에서 보이는 이름이 변경되지만, 내부 DB 쓰기 동작은 여전히 원본 컬럼을 대상으로 수행됩니다. 따라서 BDEF는 둘을 매개해 줄 추가 정보가 필요합니다.
1단계 — 기본 예제: 단일 엔티티 매핑
먼저 ZTBL_SO_HEADER 라는 데이터베이스 테이블을 가정합니다. 이 테이블의 컬럼명은 짧고 기술적인 이름으로 되어 있습니다.
@EndUserText.label : 'Sales Order Header Table'
define table ztbl_so_header {
key client : abap.clnt not null;
key so_uuid : sysuuid_x16 not null;
so_id : abap.numc(10);
cust_id : abap.char(10);
net_amt : abap.curr(15,2);
curr_cd : abap.cuky;
crt_by : abap.user;
crt_at : timestampl;
lst_chg_by : abap.user;
lst_chg_at : timestampl;
loc_lst_chg_at : timestampl;
}
위 테이블을 바탕으로 한 CDS Root View 엔티티는 다음과 같이 의미 중심의 필드명을 사용합니다.
@AccessControl.authorizationCheck: #CHECK
define root view entity ZR_SalesOrderHeader
as select from ztbl_so_header
{
key so_uuid as SalesOrderUUID,
so_id as SalesOrderId,
cust_id as CustomerId,
net_amt as NetAmount,
curr_cd as CurrencyCode,
@Semantics.user.createdBy: true
crt_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
crt_at as CreatedAt,
@Semantics.user.lastChangedBy: true
lst_chg_by as LastChangedBy,
@Semantics.systemDateTime.lastChangedAt: true
lst_chg_at as LastChangedAt,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
loc_lst_chg_at as LocalLastChangedAt
}
이제 Managed BDEF에서 매핑 절을 선언합니다. corresponding 키워드와 함께 각 CDS 필드명과 DB 컬럼명을 1:1로 매핑합니다.
managed implementation in class zbp_r_salesorderheader unique;
strict ( 2 );
define behavior for ZR_SalesOrderHeader alias SalesOrder
persistent table ztbl_so_header
lock master
authorization master ( instance )
etag master LocalLastChangedAt
{
create;
update;
delete;
field ( readonly, numbering : managed ) SalesOrderUUID;
field ( readonly ) CreatedBy, CreatedAt,
LastChangedBy, LastChangedAt,
LocalLastChangedAt;
mapping for ztbl_so_header
{
SalesOrderUUID = so_uuid;
SalesOrderId = so_id;
CustomerId = cust_id;
NetAmount = net_amt;
CurrencyCode = curr_cd;
CreatedBy = crt_by;
CreatedAt = crt_at;
LastChangedBy = lst_chg_by;
LastChangedAt = lst_chg_at;
LocalLastChangedAt = loc_lst_chg_at;
}
}
2단계 — 실무 시나리오: 자식 엔티티와 EML 호출 시 필드 참조
실무에서는 헤더-아이템 구조가 일반적입니다. ZTBL_SO_ITEM 테이블과 그 위에 정의된 CDS Projection을 통해 매핑이 적용된 상태에서 EML로 INSERT 동작을 수행하는 예제를 살펴봅니다.
define behavior for ZR_SalesOrderItem alias SalesOrderItem
persistent table ztbl_so_item
lock dependent by _SalesOrder
authorization dependent by _SalesOrder
etag master LocalLastChangedAt
{
update;
delete;
field ( readonly ) SalesOrderUUID, SalesOrderItemUUID;
field ( mandatory ) Material, Quantity;
association _SalesOrder;
mapping for ztbl_so_item
{
SalesOrderUUID = so_uuid;
SalesOrderItemUUID = soitem_uuid;
ItemPosition = item_pos;
Material = matnr;
Quantity = qty;
QuantityUnit = qty_unit;
NetItemAmount = net_item_amt;
}
}
EML에서 데이터를 INSERT할 때는 항상 CDS Projection 필드명을 사용해야 합니다. DB 컬럼명을 직접 적으면 컴파일 오류가 발생합니다.
METHOD create_sales_order_item.
DATA: lt_create_items TYPE TABLE FOR CREATE ZR_SalesOrder\_Item.
lt_create_items = VALUE #(
( %cid = 'NEW_ITEM_001'
SalesOrderUUID = is_header-SalesOrderUUID
%target = VALUE #(
( %cid = 'ITEM_TARGET_01'
ItemPosition = '0010'
Material = 'MAT-CR-2280'
Quantity = '5.000'
QuantityUnit = 'EA'
NetItemAmount = '199.99' ) ) ) ).
MODIFY ENTITIES OF ZR_SalesOrderHeader
ENTITY SalesOrder
CREATE BY \_Item FIELDS ( ItemPosition Material Quantity QuantityUnit NetItemAmount )
WITH lt_create_items
FAILED DATA(failed)
MAPPED DATA(mapped)
REPORTED DATA(reported).
IF failed-salesorderitem IS NOT INITIAL.
" 매핑 누락이나 잘못된 필드명 참조 시 여기서 실패 정보가 채워짐
LOG-POINT ID zsales_log FIELDS sy-uname failed reported.
ENDIF.
ENDMETHOD.
3단계 — 프로덕션: Late Numbering과 Draft 결합
매핑은 단순히 이름 변환에 그치지 않고, Late Numbering이나 Draft 같은 고급 기능과 결합될 때 신중한 설계가 필요합니다. Late Numbering은 SAVE 단계에서 키 값을 결정하므로, BDEF에 추가 키 매핑이 정확히 선언되어야 합니다.
define behavior for ZR_PurchaseRequisition alias PurchaseReq
persistent table ztbl_pr_header
draft table ztbl_pr_header_d
lock master total etag LastChangedAt
authorization master ( instance )
late numbering
etag master LocalLastChangedAt
{
create;
update;
delete;
draft action Activate optimized;
draft action Discard;
draft action Edit;
draft action Resume;
draft determine action Prepare;
field ( readonly, numbering : managed ) PurchaseReqUUID;
field ( readonly ) PurchaseReqNo;
mapping for ztbl_pr_header
{
PurchaseReqUUID = pr_uuid;
PurchaseReqNo = pr_no;
RequesterId = req_id;
CostCenter = cost_ctr;
TotalAmount = tot_amt;
CurrencyCode = curr_cd;
LocalLastChangedAt = loc_lst_chg_at;
}
}
Draft 시나리오에서는 Active 테이블(ztbl_pr_header)과 Draft 테이블(ztbl_pr_header_d)의 컬럼 구조가 동일해야 합니다. 매핑 절은 Active 테이블에 대해 한 번 선언하면 Draft 테이블에도 동일하게 적용됩니다. 단, Draft 테이블의 추가 관리 컬럼(DraftUUID, DraftEntityCreationDateTime 등)은 CDS Projection에서 표준 어노테이션으로 자동 처리되므로 직접 매핑할 필요가 없습니다.
Late Numbering Handler 클래스에서는 매핑된 키 필드명을 그대로 사용합니다.
METHOD adjust_numbers.
LOOP AT mapped-purchasereq ASSIGNING FIELD-SYMBOL(<fs_mapped>).
<fs_mapped>-PurchaseReqNo =
|PR-{ cl_abap_context_info=>get_system_date( ) }-{ sy-tabix WIDTH = 4 PAD = '0' }|.
ENDLOOP.
ENDMETHOD.
매핑 관련 자주 발생하는 오류와 해결법
매핑 절은 작은 오타 하나로도 활성화 자체가 실패하거나, 런타임에 데이터 손실로 이어질 수 있습니다. 대표적인 사례를 FAQ 형태로 정리합니다.
Q1. "Field XYZ is not defined in entity" 오류가 활성화 시 발생합니다.
매핑 좌변(CDS 필드명)이 실제 CDS Projection에 존재하지 않을 때 발생합니다. CDS View에서 별칭이 누락되었거나, Projection 레이어에서 필드를 노출하지 않은 경우 흔합니다. strict ( 2 ) 모드는 모든 필드의 매핑을 강하게 검증하므로, 누락된 필드가 있으면 활성화가 차단됩니다.
Q2. MODIFY가 성공했는데 DB에 값이 들어가지 않습니다.
대부분 우변(DB 컬럼명) 철자가 잘못 적힌 경우입니다. 컴파일러는 우변을 검사하지 않고 경고 없이 통과시키는 경우가 있어, 활성화는 성공하지만 런타임 INSERT가 NULL을 기록합니다. ABAP Dictionary에서 컬럼명을 복사해 붙여넣는 습관을 들이는 것이 안전합니다.
Q3. corresponding 키워드를 빼면 어떻게 되나요?
mapping for ztbl_so_header corresponding 형태로 작성하면, 명시되지 않은 필드는 동일 이름이라고 가정해 자동 매핑됩니다. corresponding을 생략하고 모든 필드를 직접 선언하는 방식이 명시적이지만 코드가 길어집니다. 일반적으로는 키 필드와 이름이 다른 필드만 명시하고 나머지는 corresponding으로 처리하는 패턴이 권장됩니다.
Q4. Draft 활성화 후 매핑을 변경했더니 기존 Draft 데이터가 깨졌습니다.
매핑 절 변경은 Draft 테이블 구조와 직접 연관됩니다. 운영 중인 Draft가 있는 상태에서 매핑을 변경할 때는 Draft 테이블을 비우는 클린업 작업이 권장되며, 변경 전후 영향 분석이 필요합니다.
실무 적용 후 살펴볼 심화 주제
매핑 절을 안정적으로 사용할 수 있게 되었다면 다음 주제로 학습 범위를 넓혀가는 것을 권장합니다. CDS Projection에 Virtual Element를 추가해 DB 컬럼이 없는 계산 필드를 노출하는 방법, Unmanaged Save 시나리오에서 매핑이 어떻게 다르게 동작하는지, 그리고 다중 백엔드 테이블을 한 CDS 엔티티로 통합할 때의 키 매핑 전략 등이 대표적입니다. 또한 Behavior Implementation Class에서 READ ENTITIES를 활용한 필드 선택적 조회와 매핑의 상호 작용도 깊이 있게 살펴볼 만한 영역입니다.
공식 문서 및 심화 자료
- help.sap.com — ABAP RAP Behavior Definition Mapping 절 레퍼런스
- help.sap.com — CDS Behavior Definitions 전체 문법 가이드
- help.sap.com — Managed RAP Business Object 설계 가이드
- help.sap.com — Late Numbering 시나리오와 키 결정 절차
- help.sap.com — Draft Handling 활성화 및 테이블 구성 절차
- SAP Developers — RAP100 핸즈온 실습 모음
- SAP Community — ABAP RAP 토픽 페이지
댓글 0
아직 댓글이 없습니다.