개요 및 핵심 포인트
SAP 시스템은 태생부터 다국어 환경이었습니다. 독일 본사에서 만든 마스터 데이터가 미국 지사에서는 영어로, 한국 지사에서는 한국어로 표시되어야 하는 요구사항이 기본값이었죠. 전통적인 ABAP 개발자라면 이런 상황에서 반사적으로 "T 테이블(Text 테이블)을 만들자"라고 생각합니다. 하지만 S/4HANA와 ABAP RESTful Application Programming Model(RAP) 시대에는 CDS(Core Data Services) Text View라는 훨씬 더 선언적이고 강력한 방법이 있습니다.
이 글에서 다룰 내용을 미리 정리해봅니다.
- CDS Text View의 정의와 존재 이유 이해
- 기존 T 테이블 방식과 CDS Text View 방식의 아키텍처 비교
@ObjectModel.text.association,@Semantics.language어노테이션의 실제 동작- SalesOrder 시나리오로 다국어 텍스트 연결 실전 구현
- Fiori Elements 및 Value Help에서 자동으로 텍스트가 표시되는 원리
- SY-LANGU와
$session.system_language의 차이 및 프로덕션 이슈 회피 전략
사전에 알아두면 좋은 개념
이 글의 예제를 온전히 이해하려면 몇 가지 배경 지식이 필요합니다. 첫째, CDS View의 기본 문법(define view, association)에 대한 최소한의 익숙함. 둘째, ABAP Dictionary에서 언어 종속 데이터 요소(Data Element)를 다뤄본 경험. 셋째, SAP GUI의 SE11에서 클라이언트(MANDT)와 언어(SPRAS) 키의 역할에 대한 이해. RAP나 Fiori Elements 경험이 있다면 후반부 실전 코드가 더 잘 와닿을 것입니다.
개발 환경 및 준비 사항
이 글의 코드 예제는 다음 환경에서 검증된 문법을 기준으로 작성되었습니다.
- SAP S/4HANA 2022 이상 (Cloud Edition 또는 On-Premise)
- ABAP Platform 2022 (ABAP Language Version 7.58+)
- ADT(ABAP Development Tools) for Eclipse 3.34 이상
- HANA DB 2.0 SPS06 이상 (Text View의 카디널리티 최적화 관련)
- SAP GUI 대신 Eclipse ADT 사용 권장 (CDS 편집기 및 어노테이션 자동완성 지원)
다국어 데이터 검증을 위해 클라이언트에 최소 2개 이상의 언어(예: EN, KO, DE)가 임포트되어 있어야 하며, SU01에서 테스트 사용자의 로그온 언어를 전환하여 결과를 확인할 수 있어야 합니다.
왜 CDS Text View가 필요한가
먼저 문제 상황을 짚어봅시다. 전통적인 ABAP에서 언어 종속 텍스트를 저장하는 표준 패턴은 두 개의 테이블 쌍이었습니다.
- 마스터 테이블: 예를 들어
ZTSO_ORDERTYPE— 언어와 무관한 코드(ORDER_TYPE)와 속성만 저장 - 텍스트 테이블(T 테이블): 예를 들어
ZTSO_ORDERTYPET— 클라이언트, 언어(SPRAS), 코드 키에 대응하는 설명 텍스트(DESCRIPTION)를 저장
이 방식은 견고하지만, 개발자가 값을 화면에 표시할 때마다 매번 언어 필터링 로직을 손으로 짜야 한다는 부담이 있었습니다. Open SQL에서 WHERE spras = sy-langu를 잊어버리면 곧바로 결과가 중복되거나 엉뚱한 언어로 표시되었죠. 또한 Fiori나 OData 클라이언트에서 "코드와 그에 해당하는 텍스트를 한 세트로" 다루려면 별도의 매핑 코드를 반복 작성해야 했습니다.
CDS Text View는 이 반복을 어노테이션 기반의 선언적 관계로 대체합니다. 비유하자면 T 테이블 방식이 "매번 사전을 손으로 뒤져서 번역하는 것"이라면, CDS Text View는 "책마다 다국어 자막 트랙이 자동으로 붙어 있는 스트리밍 서비스"에 가깝습니다. 개발자는 "이 코드 필드의 텍스트는 저 뷰에서 가져와라"라고 한 번 선언하고, 나머지는 프레임워크가 현재 세션 언어를 감지해서 알아서 처리합니다.
핵심 어노테이션 세 가지를 미리 정리합니다.
@ObjectModel.dataCategory: #TEXT— 이 뷰가 텍스트 전용 뷰임을 선언@Semantics.language: true— 이 필드가 언어 키임을 표시 (자동 필터링 대상)@Semantics.text: true— 이 필드가 실제 표시될 텍스트임을 표시
3단계 실전 구현
1단계: 기본 예제 — 주문 유형 코드와 텍스트
영업 주문 유형(Sales Order Type) 코드를 마스터로 관리하고, 각 코드에 대한 다국어 설명을 CDS Text View로 연결하는 최소 예제입니다.
-- ZTSO_ORDTYP (마스터 테이블)
CLIENT MANDT CLNT(3)
ORDER_TYPE CHAR(4) Key
CATEGORY CHAR(10)
CREATED_ON DATS
-- ZTSO_ORDTYPT (텍스트 테이블)
CLIENT MANDT CLNT(3)
LANGUAGE SPRAS LANG(1) Key
ORDER_TYPE CHAR(4) Key
DESCRIPTION CHAR(60)
이제 텍스트 뷰를 정의합니다.
@AbapCatalog.sqlViewName: 'ZVSO_ORDTYPT'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Order Type - Text View'
@ObjectModel.dataCategory: #TEXT
@ObjectModel.representativeKey: 'orderType'
define view Z_I_SalesOrderTypeText
as select from ztso_ordtypt
{
key @Semantics.language: true
language as Language,
key order_type as OrderType,
@Semantics.text: true
description as Description
}
여기서 눈여겨볼 지점은 @ObjectModel.dataCategory: #TEXT와 @Semantics.language: true입니다. 이 두 어노테이션이 있어야 이후 마스터 뷰에서 "텍스트 파트너"로 인식됩니다. @ObjectModel.representativeKey는 언어를 제외한 실제 비즈니스 키(OrderType)를 지정합니다.
이제 마스터 뷰가 텍스트 뷰를 참조하도록 연결합니다.
@AbapCatalog.sqlViewName: 'ZVSO_ORDTYP'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Type'
@ObjectModel.representativeKey: 'orderType'
define view Z_I_SalesOrderType
as select from ztso_ordtyp
association [0..*] to Z_I_SalesOrderTypeText as _Text
on $projection.orderType = _Text.OrderType
{
@ObjectModel.text.association: '_Text'
key order_type as OrderType,
category as Category,
created_on as CreatedOn,
_Text
}
@ObjectModel.text.association: '_Text' 한 줄이 마법의 열쇠입니다. 이 어노테이션 덕분에 Value Help, Fiori Elements, OData 클라이언트가 OrderType을 표시할 때 자동으로 _Text 어소시에이션을 따라가 현재 세션 언어의 Description을 함께 반환합니다.
2단계: 실무 시나리오 — 세션 언어 필터링과 폴백 처리
실무에서는 사용자가 한국어(KO)로 로그온했지만 특정 마스터 데이터에 한국어 번역이 없는 경우가 흔합니다. 이때 완전히 빈 값이 반환되면 화면이 비어버리는 사고가 발생합니다. 세션 언어를 명시적으로 필터링하고, 필요 시 영어(EN) 폴백을 제공하는 확장 뷰를 만들어봅시다.
@AbapCatalog.sqlViewName: 'ZVSO_ORDTYP_C'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Type - Consumption with Fallback'
@Metadata.allowExtensions: true
define view Z_C_SalesOrderTypeWithText
as select from Z_I_SalesOrderType as OrderType
left outer join Z_I_SalesOrderTypeText as PrimaryText
on OrderType.OrderType = PrimaryText.OrderType
and PrimaryText.Language = $session.system_language
left outer join Z_I_SalesOrderTypeText as FallbackText
on OrderType.OrderType = FallbackText.OrderType
and FallbackText.Language = 'E'
{
key OrderType.OrderType,
OrderType.Category,
OrderType.CreatedOn,
coalesce( PrimaryText.Description,
FallbackText.Description,
cast( 'No description' as abap.char( 60 ) )
) as DisplayDescription,
case
when PrimaryText.Description is not initial then 'PRIMARY'
when FallbackText.Description is not initial then 'FALLBACK'
else 'MISSING'
end as TextSource
}
여기서 $session.system_language를 SY-LANGU 대신 사용한 점에 주목해야 합니다. CDS는 ABAP 세션 변수를 직접 참조할 수 없으므로 $session.* 프리픽스로 접근합니다. TextSource 컬럼은 운영 중 어느 언어에서 값이 왔는지 모니터링용 정보를 제공합니다.
3단계: 프로덕션 — RAP Behavior와 성능 튜닝
실제 배포 환경에서는 CDS Text View를 RAP Behavior Definition과 Metadata Extension까지 결합해 사용합니다. Fiori Elements의 List Report가 자동으로 "코드 + 설명" 포맷으로 렌더링되도록 하는 설정입니다.
// Metadata Extension
@Metadata.layer: #CORE
annotate view Z_C_SalesOrderTypeWithText with
{
@UI.lineItem: [ { position: 10, label: 'Order Type' } ]
@UI.identification: [ { position: 10 } ]
@UI.textArrangement: #TEXT_FIRST
OrderType;
@UI.lineItem: [ { position: 20, label: 'Category' } ]
Category;
@UI.hidden: true
DisplayDescription;
}
@UI.textArrangement: #TEXT_FIRST는 "설명(코드)" 형태로 표시하라는 지시입니다. #TEXT_LAST, #TEXT_ONLY, #TEXT_SEPARATE 옵션도 요구사항에 따라 선택할 수 있습니다.
성능 관점에서는 다음 세 가지를 반드시 점검합니다.
- 인덱스: T 테이블의 (LANGUAGE, ORDER_TYPE) 조합에 세컨더리 인덱스가 없으면 대량 조회 시 풀 스캔 발생. SE11에서 인덱스 추가 필수.
- Buffering: 텍스트 테이블은 변경 빈도가 낮고 읽기 빈도가 극도로 높으므로 Generic Buffering(언어 키 기준)을 권장.
- Test Class: CDS Test Double Framework(
cl_cds_test_environment)로 언어별 텍스트 반환을 유닛 테스트로 검증.
CLASS ltcl_sales_order_type_text DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
METHODS setup.
METHODS korean_language_returns_kor FOR TESTING RAISING cx_static_check.
METHODS missing_translation_falls_back FOR TESTING RAISING cx_static_check.
ENDCLASS.
CLASS ltcl_sales_order_type_text IMPLEMENTATION.
METHOD class_setup.
environment = cl_cds_test_environment=>create(
i_for_entity = 'Z_C_SALESORDERTYPEWITHTEXT' ).
ENDMETHOD.
METHOD setup.
environment->clear_doubles( ).
ENDMETHOD.
METHOD korean_language_returns_kor.
DATA(text_doubles) = VALUE ztso_ordtypt_tab(
( language = '3' order_type = 'STD1' description = '표준 주문' )
( language = 'E' order_type = 'STD1' description = 'Standard Order' )
).
environment->insert_test_data( text_doubles ).
" 세션 언어 KO 설정 후 Description = '표준 주문' 검증
ENDMETHOD.
ENDCLASS.
자주 마주치는 함정과 해결책
Q1. CDS Text View를 활성화했는데 Fiori 화면에 여전히 코드만 표시됩니다.
원인은 대개 세 가지 중 하나입니다. (1) 마스터 뷰의 코드 필드에 @ObjectModel.text.association을 붙이지 않았거나, (2) 어소시에이션 이름 철자 오류, (3) Metadata Extension에서 @UI.textArrangement를 지정하지 않음. Eclipse에서 Ctrl+F3으로 뷰를 열어 활성 상태를 확인하고, /IWFND/CACHE_CLEANUP으로 게이트웨이 캐시를 청소한 뒤 재시도합니다.
Q2. SY-LANGU와 $session.system_language는 무엇이 다른가요?
런타임에서는 결과값이 같지만, CDS 뷰는 데이터베이스 레벨에서 실행되므로 ABAP 시스템 필드에 직접 접근할 수 없습니다. $session은 CDS 세션 변수 인터페이스로, HANA가 이해할 수 있는 형태로 언어 정보를 주입합니다. CDS 안에서는 무조건 $session.system_language를 사용하세요.
Q3. 개발 시스템에서는 잘 되는데 QAS 이후로 텍스트가 안 나옵니다.
번역 데이터는 이송 대상이 아닌 경우가 많습니다. SE63(Translation)에서 텍스트 오브젝트를 별도 이송 요청으로 옮겨야 합니다. 또한 임포트 시 언어 지원 여부(SMLT)를 반드시 확인합니다. 특정 언어가 클라이언트에 설치되지 않았다면 2단계에서 만든 폴백 로직이 방어선이 됩니다.
Q4. 대용량 T 테이블에서 Text View 조인이 느립니다.
HANA의 언어 컬럼은 카디널리티가 매우 낮아 옵티마이저가 잘못된 계획을 선택할 수 있습니다. @Consumption.filter로 언어를 필수 필터로 지정하거나, HANA View Hint(@AbapCatalog.dbHints)로 조인 순서를 명시하는 방법이 있습니다.
이후에 파고들면 좋은 주제
CDS Text View를 이해했다면 자연스럽게 확장할 수 있는 주제들이 이어집니다. 첫째, CDS Composite View와 Value Help(@Consumption.valueHelpDefinition)를 결합해 F4 도움말에 자동으로 텍스트가 표시되도록 만드는 방법. 둘째, RAP의 Managed Behavior에서 Text 필드의 자동 생성/삭제 처리. 셋째, Analytical CDS View에서 @AnalyticsDetails.query.axis와 함께 다국어 차원(Dimension) 라벨을 처리하는 기법. 넷째, ABAP Cloud 환경에서 Released API로서의 Text View 노출과 Extensibility 고려사항.
댓글 0
아직 댓글이 없습니다.