ABAP

CDS EXTEND VIEW — 표준 뷰 수정 없이 3줄로 확장 #shorts #SAP #ABAP

개요: 표준을 건드리지 않고 확장한다는 것

S/4HANA 프로젝트에서 가장 자주 받는 요구사항 중 하나는 "표준 CDS 뷰에 우리 회사 필드 하나만 추가해 달라"입니다. 표준 뷰 소스를 직접 수정하면 당장은 동작하지만, 업그레이드 시점에 변경분이 덮어써지거나 충돌이 발생합니다. ABAP CDS의 EXTEND VIEW는 표준 뷰 원본을 그대로 둔 채 별도의 확장 오브젝트로 필드를 추가하는 메커니즘입니다. 이 글에서는 구매발주(Purchase Order) 시나리오를 예제로 확장 구문, 동작 원리, 업그레이드 안전성까지 단계별로 다룹니다.

  • EXTEND VIEW 기본 구문과 @AbapCatalog.sqlViewAppendName 이해
  • 베이스 뷰의 @AbapCatalog.viewEnhancementCategory가 확장 가능 범위를 통제하는 방식 이해
  • Association을 활용해 커스텀 테이블 데이터를 표준 뷰에 연결
  • S/4HANA 업그레이드 시 커스텀 확장이 보호되는 원리 파악

시작 전에 갖추면 좋은 배경

CDS 뷰 기본 문법(SELECT, Association, 어노테이션)을 작성해 본 경험이 있다면 충분합니다. DDIC의 Append Structure 개념을 알고 있으면 확장 필드가 어디서 오는지 빠르게 이해할 수 있습니다. ADT(ABAP Development Tools in Eclipse) 사용 경험도 필요합니다. CDS 뷰는 SE11이 아니라 ADT에서만 편집할 수 있기 때문입니다.

환경과 버전 조건

이 예제는 다음 환경을 기준으로 합니다.

  • S/4HANA 온프레미스 1909 이상 (DDIC 기반 CDS 뷰의 EXTEND VIEW는 NetWeaver 7.40 SP05부터 사용 가능)
  • CDS View Entity 확장(EXTEND VIEW ENTITY)을 쓰려면 S/4HANA 2020(ABAP Platform 7.55) 이상이 필요합니다
  • ADT 최신 버전 + 개발 시스템 접속 권한(S_DEVELOP)
  • 확장 필드의 원천이 되는 테이블 확장: 예제에서는 EKKO에 Append Structure로 ZZ1_DELIVERY_PRIORITY 필드가 추가되어 있다고 가정합니다

SAP BTP ABAP Environment나 S/4HANA Cloud Public Edition에서는 Released API 여부와 확장 계약(C0 contract)에 따라 확장 가능 오브젝트가 제한되므로, 온프레미스보다 먼저 릴리스 상태를 확인하는 것이 일반적으로 권장됩니다.

핵심 개념: EXTEND VIEW는 어떻게 동작하는가

EXTEND VIEW를 비유하자면 "표준 뷰라는 건물에 증축 허가를 받아 별관을 붙이는 것"입니다. 본관(표준 뷰) 설계도는 전혀 수정하지 않고, 별관(확장 뷰)은 독립된 도면(별도 오브젝트, Z 네임스페이스)으로 관리됩니다. 활성화 시점에 시스템이 두 도면을 합쳐 하나의 건물처럼 보이게 만듭니다.

기술적으로 정리하면 다음과 같습니다.

  • 별도 오브젝트로 저장: 확장은 DDLX가 아닌 DDLS(뷰 확장 정의)로 저장되며, 표준 뷰의 소스 코드는 1바이트도 변경되지 않습니다. 이것이 업그레이드 안전성의 핵심입니다. SAP이 표준 뷰를 새 버전으로 교체해도 고객의 확장 오브젝트는 Z 네임스페이스에 그대로 남고, 활성화 시 다시 병합됩니다.
  • DDIC 레벨 병합: DDIC 기반 CDS 뷰의 경우 확장 필드는 @AbapCatalog.sqlViewAppendName으로 지정한 Append View를 통해 데이터베이스 뷰의 SELECT 리스트 끝에 덧붙습니다. 결과적으로 표준 뷰를 SELECT하는 모든 코드(Fiori 앱, OData 서비스 포함)에서 확장 필드가 보입니다.
  • 확장 허용 통제: 베이스 뷰는 @AbapCatalog.viewEnhancementCategory 어노테이션으로 확장 가능 범위를 선언합니다. #PROJECTION_LIST면 필드·Association 추가가 허용되고, #NONE이면 확장 자체가 차단됩니다. 집계(GROUP BY)나 UNION이 있는 뷰는 #GROUP_BY, #UNION이 함께 선언되어야 해당 구조까지 확장할 수 있습니다. 확장을 시도하면 활성화 시점에 이 허용 검사가 수행되어, 허용되지 않은 확장은 에러로 거부됩니다.
  • Association 추가 가능: 확장에서는 단순 필드뿐 아니라 새로운 Association도 선언할 수 있습니다. Association은 "필요할 때만 실행되는 지연 조인(join on demand)"이므로, 확장 뷰에 Association을 추가해도 이를 사용하지 않는 기존 쿼리의 성능에는 일반적으로 영향이 없습니다.

주의할 점은 확장이 "읽기 구조의 확장"이라는 것입니다. WHERE 조건 변경, 기존 필드 삭제·수정은 불가능합니다. 어디까지나 프로젝션 리스트에 덧붙이는 방식이므로, 표준 뷰의 의미(semantics)를 깨뜨릴 수 없다는 점이 오히려 안전장치로 작동합니다.

실전 코드: 3단계로 완성하는 구매발주 뷰 확장

1단계 — 기본 예제: 테이블 확장 필드를 표준 뷰에 노출

EKKO에 Append Structure로 추가된 납품 우선순위 필드 ZZ1_DELIVERY_PRIORITY를 구매발주 표준 뷰에 노출한다고 가정합니다. 먼저 베이스 뷰가 확장 가능한지 확인합니다. 표준 뷰 소스 상단에 아래와 같은 어노테이션이 있어야 합니다.

// 베이스 뷰(표준) 측 선언 예시 — 직접 수정하지 않고 확인만 합니다
@AbapCatalog.viewEnhancementCategory: [#PROJECTION_LIST]

확인 후 ADT에서 New > Data Definition을 만들고, 템플릿 대신 직접 EXTEND 구문을 작성합니다.

@AbapCatalog.sqlViewAppendName: 'ZXPOHDRPRIO'
@EndUserText.label: '구매발주 헤더 - 납품우선순위 확장'
extend view I_PurchaseOrderApi01 with ZX_PurchaseOrder_Prio
{
  _PurchaseOrder.zz1_delivery_priority as ZzDeliveryPriority
}

포인트는 세 가지입니다. 첫째, sqlViewAppendName은 DDIC에 생성될 Append View의 기술적 이름으로 16자 제한이 있습니다. 둘째, 확장 이름(ZX_PurchaseOrder_Prio)은 고객 네임스페이스로 시작해야 합니다. 셋째, 확장 필드는 베이스 뷰의 데이터 소스(위 예에서는 표준 뷰 내부의 소스 별칭)를 통해 접근합니다. 활성화하면 즉시 SELECT ZzDeliveryPriority FROM I_PurchaseOrderApi01이 가능해집니다.

2단계 — 실무 시나리오: 커스텀 테이블 Association과 방어적 처리

실무에서는 단일 필드 추가로 끝나지 않습니다. 예를 들어 구매팀이 자체 관리하는 공급업체 등급 테이블 ztpu_vendor_rate(키: 공급업체 번호)를 표준 뷰에 연결해 등급과 평가일을 함께 조회하고 싶다는 요구가 있다고 합시다. 확장에서 Association을 새로 선언하면 됩니다.

@AbapCatalog.sqlViewAppendName: 'ZXPOVDRATE'
@EndUserText.label: '구매발주 - 공급업체 등급 확장'
extend view I_PurchaseOrderApi01 with ZX_PurchaseOrder_VendorRate
  association [0..1] to ztpu_vendor_rate as _VendorRating
    on $projection.Supplier = _VendorRating.supplier_id
{
  _VendorRating,   // Association 자체를 노출 (지연 조인)

  // 등급이 없는 신규 공급업체 대비: NULL 방어
  case
    when _VendorRating.rating_grade is null then 'N/A'
    else _VendorRating.rating_grade
  end as VendorRatingGrade,

  _VendorRating.evaluated_on as VendorRatedOn
}

여기서 카디널리티 [0..1]이 중요합니다. 등급 데이터가 없는 공급업체가 존재할 수 있으므로 [1..1]로 선언하면 옵티마이저가 INNER JOIN에 준하는 가정을 할 수 있어 결과가 달라질 위험이 있습니다. 또한 CASE로 NULL을 방어하면 Fiori 화면에서 빈 값 대신 'N/A'가 표시되어 운영 문의를 줄일 수 있습니다. 확장이 활성화되지 않을 때는 ADT의 Problems 뷰와 함께, 실행 시 이상 징후는 ST22(덤프)와 SQL 트레이스(ST05)로 원인을 추적하는 것이 일반적인 진단 흐름입니다.

3단계 — 프로덕션 수준: View Entity 확장, 성능, 테스트

S/4HANA 2020 이상이라면 신규 개발은 CDS View Entity 기반이 표준 방향이며, 확장 구문도 달라집니다. Append View가 필요 없어 sqlViewAppendName 어노테이션이 사라지고 구문이 간결해집니다.

@EndUserText.label: '구매발주 View Entity 확장'
extend view entity ZI_PurchaseOrderHdr with
  association [0..1] to ztpu_vendor_rate as _VendorRating
    on $projection.Supplier = _VendorRating.supplier_id
{
  _VendorRating,
  _VendorRating.rating_grade as VendorRatingGrade
}

프로덕션 반영 전 체크리스트는 다음과 같습니다.

  • 성능: 확장에서 [0..1]·[1..1] Association의 필드를 프로젝션 리스트에 직접 노출하면 해당 필드를 조회하는 순간 LEFT OUTER JOIN이 발생합니다. 대량 조회 리스트 뷰라면 필드 노출 대신 Association만 노출하고, 소비 측에서 필요할 때 경로 표현식으로 접근하게 하는 편이 유리합니다. 반영 후에는 PlanViz나 SQL 트레이스로 실행 계획을 확인합니다.
  • 테스트: CDS Test Double Framework(cl_cds_test_environment)로 확장 필드가 기대대로 채워지는지 단위 테스트를 작성합니다. 확장 뷰 자체는 테스트 대상이 아니지만, 확장 필드를 소비하는 Z 뷰나 클래스에 대해 테이블 더블을 심어 검증할 수 있습니다.
  • 보안: 확장 필드가 민감 정보(단가, 평가 등급 등)라면 베이스 뷰의 DCL(Access Control)이 확장 필드까지 자동으로 행 단위 보호를 적용하는지 확인해야 합니다. DCL은 행 필터이므로 열 단위 노출 통제가 필요하면 소비 계층에서 별도 처리가 필요합니다.
  • 이관: 확장 DDLS와 테이블 Append는 같은 트랜스포트로 묶어 순서 문제를 방지합니다.

흔한 실수와 트러블슈팅 FAQ

Q1. "View is not extendable" 에러가 납니다.
베이스 뷰의 @AbapCatalog.viewEnhancementCategory#NONE이거나 어노테이션이 없는 구버전 뷰일 수 있습니다. 이 경우 표준 뷰 확장은 불가능하며, 표준 뷰를 SELECT 소스로 삼는 자체 래퍼(Z) 뷰를 만들어 조인하는 우회가 일반적입니다. 표준 수정(Modification)은 최후의 수단으로도 권장되지 않습니다.

Q2. sqlViewAppendName 관련 활성화 오류가 발생합니다.
DDIC 기반 뷰 확장에서 Append View 이름이 16자를 넘거나 이미 존재하는 이름일 때 발생합니다. 반대로 View Entity를 확장하면서 sqlViewAppendName을 넣어도 오류가 납니다. 베이스가 DEFINE VIEW인지 DEFINE VIEW ENTITY인지 먼저 확인하고 구문을 맞추세요.

Q3. 집계가 있는 표준 뷰를 확장했더니 GROUP BY 오류가 납니다.
집계 뷰에 필드를 추가하면 그 필드는 GROUP BY에도 반영되어야 합니다. 베이스 뷰가 #GROUP_BY 카테고리를 허용해야 하고, 확장 필드가 집계 단위를 바꿔 결과 행 수가 달라질 수 있으므로 기존 소비처 검증이 필수입니다.

Q4. 확장 필드가 Fiori 앱에 안 보입니다.
뷰 레벨 확장과 UI 노출은 별개입니다. OData 서비스 재생성(또는 메타데이터 캐시 초기화)과 UI 어노테이션(메타데이터 확장 또는 Custom Fields 앱 처리)이 추가로 필요합니다.

여기서 더 나아가기

EXTEND VIEW를 익혔다면 자연스럽게 이어지는 주제는 세 가지입니다. 첫째, Metadata Extension(DDLX) — 데이터 구조가 아닌 UI 어노테이션을 계층적으로 확장하는 방법으로, 확장 필드를 Fiori 화면에 배치할 때 함께 쓰입니다. 둘째, Key User Extensibility(Custom Fields 앱) — 코드 없이 필드를 추가하면 시스템이 내부적으로 CDS 확장을 생성해 주는 방식과의 역할 분담을 이해하면 설계 판단이 빨라집니다. 셋째, RAP BDEF Extension — 조회 확장을 넘어 트랜잭션 동작까지 확장하는 S/4HANA 최신 확장 모델입니다.

참고할 만한 문서와 링크

댓글 0

아직 댓글이 없습니다.