ABAP

CRHD vs CDS 뷰 — 작업장 능력 차이 #shorts #SAP #ABAP

▶ YouTube에서 보기

I_WorkCenterCapacity CDS 뷰 개요 — 왜 CRHD를 버려야 하는가

SAP S/4HANA의 생산 관련 개발에서 작업장(Work Center) 능력 데이터를 다룰 때, 많은 개발자가 여전히 CRHD, CRCA, KAKO 테이블을 직접 조인하는 레거시 방식을 사용합니다. 이 글에서는 SAP가 S/4HANA VDM(Virtual Data Model)의 일부로 제공하는 I_WorkCenterCapacity CDS 뷰를 활용하여, 물리 테이블 조인 없이 작업장 능력 데이터를 읽는 실전 접근법을 다룹니다.

이 글을 끝까지 읽으면 다음을 할 수 있습니다.

  • CRHD·CRCA·KAKO 물리 테이블 조인을 I_WorkCenterCapacity 단일 SELECT로 대체
  • CDS Association으로 작업장 마스터·능력 헤더 데이터에 JOIN 문 없이 접근
  • 커스텀 CDS 뷰 + OData로 작업장 능력 조회 API 설계
  • 생산 계획 능력 검증 로직을 프로덕션 수준으로 구현

대상 환경: SAP S/4HANA 2022 이상 On-Premise 또는 S/4HANA Cloud(Public/Private Edition), 개발 도구는 ADT(ABAP Development Tools for Eclipse)를 기준으로 합니다. ABAP Cloud(언어 버전 5, ABAP for Cloud Development) 환경에서는 릴리스된 CDS 뷰만 접근 가능하므로 I_WorkCenterCapacity 활용이 사실상 필수입니다. 사전에 CDS 뷰 기본 문법, Open SQL(ABAP SQL), Association 개념을 알고 있으면 이해가 빠릅니다. 진행 전 ADT에서 I_WorkCenterCapacity를 열어(Ctrl+Shift+A) 본인 시스템 릴리스의 필드 구성과 릴리스 계약(Release Contract) 상태를 확인하는 것을 권장합니다. 릴리스마다 필드가 추가·변경될 수 있기 때문입니다.

CRHD·CRTX·KAKO 테이블 구조와 CDS 뷰 전환의 이유

작업장 능력 데이터는 전통적으로 여러 테이블에 분산되어 있습니다.

테이블역할주요 키
CRHD작업장 헤더 (Work Center Header)OBJTY + OBJID
CRTX작업장 텍스트 (언어별 명칭)OBJTY + OBJID + SPRAS
CRCA작업장-능력 할당 (Capacity Allocation)OBJID + KAPID
KAKO능력 헤더 (가동 시간, 가동률, 개별 능력 수)KAPID

레거시 방식으로 "특정 플랜트의 작업장별 능력"을 조회하려면 최소 3개 테이블을 조인해야 하고, OBJTY = 'A'(작업장 유형) 같은 기술적 필터를 개발자가 매번 기억해야 했습니다. 이를 비유하자면 도서관에서 책을 찾을 때 서가 배치도(테이블 구조)를 외워서 직접 돌아다니는 것과 같습니다. 반면 CDS 뷰는 사서에게 책 제목만 말하면 되는 방식입니다. 시맨틱한 필드명(WorkCenterInternalID, CapacityInternalID)이 기술 키(OBJID, KAPID)를 감싸고, 유형 필터 같은 상투적 조건은 뷰 내부에 이미 반영되어 있습니다.

CDS 뷰 전환의 실질적 이점은 다음과 같습니다.

  • 업그레이드 안정성: 릴리스된 VDM 뷰는 SAP의 릴리스 계약(C1: Use in Cloud Development 등) 대상이므로, 물리 테이블 구조가 바뀌어도 뷰 인터페이스는 일반적으로 유지됩니다.
  • ABAP Cloud 호환: 3-Tier 확장 모델에서 Tier 1(클라우드 준수 개발)은 CRHD 직접 접근이 허용되지 않습니다.
  • 권한 통합: DCL(Access Control)이 뷰에 연결되어 있어 SELECT 시점에 인스턴스 권한이 자동 적용됩니다.
  • Association 기반 탐색: 조인문 없이 \_WorkCenter 같은 경로 표현식으로 연관 데이터에 접근합니다.

I_WorkCenterCapacity 핵심 필드 분석

I_WorkCenterCapacity는 작업장과 능력(Capacity) 간의 할당 관계를 표현하는 기본(Basic) 인터페이스 뷰로, 개념적으로 CRCA를 중심에 두고 관련 데이터를 시맨틱하게 노출합니다. 대표적인 필드 구성은 다음과 같습니다(정확한 목록은 ADT에서 확인 권장).

필드원천 개념설명
WorkCenterInternalIDOBJID작업장 내부 ID (키)
WorkCenterTypeCodeOBJTY오브젝트 유형 (작업장 = 'A')
CapacityInternalIDKAPID능력 내부 ID (키)
CapacityCategoryCodeKAPAR능력 범주 (기계/노동 등)

주의할 점은 이 뷰가 내부 ID 기반이라는 것입니다. 사용자가 아는 작업장 코드(예: ML-ASSY-01)와 플랜트는 \_WorkCenter Association을 통해 I_WorkCenter 뷰에서 가져와야 합니다. 능력의 가동 시작/종료 시각, 가동률, 개별 능력 수 같은 헤더 상세는 능력 헤더 계열 뷰(시스템 릴리스에 따라 뷰명이 다를 수 있음)와의 Association으로 접근합니다. 이런 계층 구조는 VDM의 설계 철학 — Basic 뷰는 정규화된 최소 단위, Composite 뷰에서 조합 — 을 그대로 반영합니다.

ABAP SELECT로 작업장 능력 데이터 읽기 — 실전 예제

3단계로 난이도를 올려가며 구현합니다. 시나리오는 "전자부품 공장의 SMT 라인 작업장 능력 조회"입니다.

1단계 — 기본 조회

" SMT 라인 작업장에 할당된 능력 목록 조회
SELECT wcc~WorkCenterInternalID,
       wcc~CapacityInternalID,
       wcc~CapacityCategoryCode
  FROM I_WorkCenterCapacity AS wcc
  INTO TABLE @DATA(lt_smt_capacity)
  UP TO 50 ROWS.

LOOP AT lt_smt_capacity INTO DATA(ls_cap).
  cl_demo_output=>write( |작업장ID: { ls_cap-WorkCenterInternalID } | &&
                         |능력ID: { ls_cap-CapacityInternalID }| ).
ENDLOOP.
cl_demo_output=>display( ).

2단계 — 실무 시나리오: 플랜트 필터 + 에러 처리 + 로깅

실무에서는 내부 ID가 아니라 플랜트·작업장 코드로 조회합니다. Association 경로 표현식으로 I_WorkCenter의 필드를 WHERE 조건에 직접 사용하고, 결과가 없을 때 Application Log에 기록합니다.

CLASS zcl_smt_capacity_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_capacity,
             work_center_id TYPE objektid,
             capacity_id    TYPE kapid,
             category_code  TYPE kapar,
           END OF ty_capacity,
           tt_capacity TYPE STANDARD TABLE OF ty_capacity WITH EMPTY KEY.

    METHODS get_by_plant
      IMPORTING iv_plant           TYPE werks_d
      RETURNING VALUE(rt_capacity) TYPE tt_capacity
      RAISING   zcx_capacity_not_found.
ENDCLASS.

CLASS zcl_smt_capacity_reader IMPLEMENTATION.
  METHOD get_by_plant.
    " Association 경로로 플랜트 필터 — 명시적 JOIN 불필요
    SELECT WorkCenterInternalID AS work_center_id,
           CapacityInternalID  AS capacity_id,
           CapacityCategoryCode AS category_code
      FROM I_WorkCenterCapacity
      WHERE \_WorkCenter-Plant = @iv_plant
      INTO TABLE @rt_capacity.

    IF rt_capacity IS INITIAL.
      " Application Log 기록 후 예외 발생
      DATA(lo_log) = cl_bali_log=>create_with_header(
        header = cl_bali_header_setter=>create(
                   object    = 'ZPP_CAP'
                   subobject = 'READ' ) ).
      lo_log->add_item( cl_bali_free_text_setter=>create(
        severity = if_bali_constants=>c_severity_warning
        text     = |플랜트 { iv_plant } 작업장 능력 데이터 없음| ) ).
      cl_bali_log_db=>get_instance( )->save_log( lo_log ).

      RAISE EXCEPTION NEW zcx_capacity_not_found( plant = iv_plant ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

3단계 — 프로덕션: 커스텀 CDS 뷰 + 테스트 격리

반복 조회되는 조합은 커스텀 CDS 뷰(Z 뷰)로 캡슐화하는 것이 성능·재사용 측면에서 유리합니다. 필요한 필드만 프로젝션하여 HANA 레벨에서 데이터 이동량을 줄입니다.

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'SMT 작업장 능력 조회 뷰'
define view entity ZI_SmtWorkCenterCapacity
  as select from I_WorkCenterCapacity
  association [1..1] to I_WorkCenter as _WorkCenterMaster
    on $projection.WorkCenterInternalID = _WorkCenterMaster.WorkCenterInternalID
{
  key WorkCenterInternalID,
  key CapacityInternalID,
      CapacityCategoryCode,
      _WorkCenterMaster.WorkCenter     as WorkCenterCode,
      _WorkCenterMaster.Plant          as Plant,
      /* 노출용 Association — 소비 시점에 필요할 때만 조인됨 */
      _WorkCenterMaster
}

단위 테스트에서는 CDS Test Double Framework로 뷰 의존성을 격리합니다.

CLASS ltc_capacity_reader DEFINITION FOR TESTING
  RISK LEVEL HARMLESS DURATION SHORT.
  PRIVATE SECTION.
    CLASS-DATA go_env TYPE REF TO if_cds_test_environment.
    METHODS empty_plant_raises_exception FOR TESTING.
ENDCLASS.

CLASS ltc_capacity_reader IMPLEMENTATION.
  METHOD empty_plant_raises_exception.
    go_env = cl_cds_test_environment=>create(
               i_for_entity = 'ZI_SMTWORKCENTERCAPACITY' ).
    go_env->clear_doubles( ).  " 빈 데이터 상태 구성

    TRY.
        NEW zcl_smt_capacity_reader( )->get_by_plant( 'KR01' ).
        cl_abap_unit_assert=>fail( '예외가 발생해야 함' ).
      CATCH zcx_capacity_not_found.
        " 기대한 동작
    ENDTRY.
    go_env->destroy( ).
  ENDMETHOD.
ENDCLASS.

CDS Association 활용 — JOIN 없이 연관 데이터 접근

Association의 핵심은 지연 조인(join on demand)입니다. 뷰 정의에 Association을 선언해도 소비하는 쿼리가 해당 경로를 사용하지 않으면 SQL 조인이 아예 생성되지 않습니다. 위 2단계 예제의 \_WorkCenter-Plant가 대표적인 경로 표현식 사용입니다. 이는 명시적 JOIN 대비 두 가지 이점이 있습니다.

  • 가독성: "작업장 능력의 작업장의 플랜트"라는 비즈니스 관계가 코드에 그대로 드러납니다.
  • 최적화 위임: 옵티마이저가 카디널리티 선언([1..1], [0..*])을 근거로 조인 전략을 선택합니다. 카디널리티를 실제와 다르게 선언하면 잘못된 조인 프루닝이 발생할 수 있으므로 정확히 선언해야 합니다.

ABAP SQL에서도 경로 표현식을 그대로 쓸 수 있습니다. 예를 들어 능력 범주별 집계는 다음과 같이 작성합니다.

SELECT CapacityCategoryCode,
       COUNT( * ) AS assignment_count
  FROM ZI_SmtWorkCenterCapacity
  WHERE Plant = 'KR01'
  GROUP BY CapacityCategoryCode
  INTO TABLE @DATA(lt_category_stats).

OData 서비스와 연동한 작업장 능력 API 설계

RAP(ABAP RESTful Application Programming Model)에서는 커스텀 뷰 위에 Consumption 뷰와 Service Definition/Binding을 얹어 조회 전용 OData V4 서비스를 만듭니다.

@EndUserText.label: '작업장 능력 API용 소비 뷰'
@Metadata.allowExtensions: true
define view entity ZC_SmtWorkCenterCapacity
  as projection on ZI_SmtWorkCenterCapacity
{
  key WorkCenterInternalID,
  key CapacityInternalID,
      WorkCenterCode,
      Plant,
      CapacityCategoryCode
}
@EndUserText.label: '작업장 능력 조회 서비스'
define service ZUI_SMT_CAPACITY {
  expose ZC_SmtWorkCenterCapacity as WorkCenterCapacity;
}

Service Binding에서 OData V4 - UI 또는 Web API 유형을 선택해 활성화하면 $filter=Plant eq 'KR01' 같은 쿼리가 HANA까지 푸시다운됩니다. 참고로 S/4HANA Cloud에는 작업장 마스터를 다루는 표준 OData API도 제공되므로(SAP Business Accelerator Hub에서 확인 가능), 외부 시스템 연동이라면 커스텀 API보다 표준 API 활용을 먼저 검토하는 것이 일반적으로 권장됩니다.

성능 고려사항, 그리고 자주 겪는 문제들

성능 관점의 핵심 원칙은 세 가지입니다.

  1. 필드 최소화: SELECT * 대신 필요한 필드만 명시해 컬럼 스토어 접근량을 줄입니다.
  2. 필터 푸시다운: WHERE 조건은 애플리케이션 레이어 필터링(LOOP + IF)이 아니라 반드시 SELECT에 포함시킵니다.
  3. 버퍼링 주의: CRHD는 전통적으로 테이블 버퍼링 대상이지만, CDS 뷰 경유 접근은 일반적으로 테이블 버퍼를 우회합니다. 대량 반복 조회가 필요하면 내부 테이블 캐싱 또는 @ClientHandling·성능 어노테이션 검토가 필요하며, 잦은 단건 조회 패턴이라면 애플리케이션 레벨에서 cl_abap_... 정적 캐시를 두는 편이 효과적입니다.

자주 나오는 질문(FAQ)을 정리합니다.

Q1. CRHD 직접 SELECT 결과와 뷰 결과 건수가 다릅니다.
A. CRHD에는 작업장 외 오브젝트 유형도 저장될 수 있고, VDM 뷰는 유형 필터·유효성 조건이 내부에 반영되어 있는 경우가 많습니다. 뷰의 데이터 정의(SQL 소스)를 ADT에서 열어 WHERE 절을 확인하세요.

Q2. SELECT는 되는데 결과가 항상 0건입니다(권한).
A. @AccessControl.authorizationCheck: #CHECK가 걸린 뷰는 DCL이 적용됩니다. SACF/권한 트레이스(STAUTHTRACE)로 인스턴스 권한 누락 여부를 확인하고, 기술 사용자라면 필요한 권한 오브젝트를 역할에 추가해야 합니다.

Q3. ADT에서 I_WorkCenterCapacity가 검색되지 않습니다.
A. 릴리스가 낮거나(초기 S/4HANA 버전) 소프트웨어 컴포넌트가 미설치된 경우입니다. ADT의 Released Objects 트리 또는 테이블 ARS_W_API_STATE 계열 정보로 릴리스 상태를 확인하고, 없으면 상위 릴리스의 대체 뷰를 SAP Business Accelerator Hub에서 검색하세요.

Q4. 경로 표현식 사용 시 성능이 급격히 나빠집니다.
A. [0..*] 카디널리티 Association을 SELECT 리스트에서 사용하면 행 폭발이 발생할 수 있습니다. 대다수(1건) 관계만 경로 표현식으로 쓰고, 다건 관계는 별도 SELECT 또는 집계로 분리하는 것이 안전합니다.

실무 시나리오 — 생산 계획 능력 검증 구현

마지막으로 실무에서 흔한 요구사항인 "생산 오더 생성 전, 대상 작업장에 활성 능력이 존재하는지 검증"을 구현합니다. 검증 로직은 인터페이스로 추상화해 BAdI나 RAP Validation에서 재사용할 수 있게 합니다.

INTERFACE zif_prodcap_validator PUBLIC.
  METHODS validate_capacity_exists
    IMPORTING iv_plant        TYPE werks_d
              iv_work_center  TYPE arbpl
    RETURNING VALUE(rv_valid) TYPE abap_bool.
ENDINTERFACE.

CLASS zcl_prodcap_validator DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES zif_prodcap_validator.
ENDCLASS.

CLASS zcl_prodcap_validator IMPLEMENTATION.
  METHOD zif_prodcap_validator~validate_capacity_exists.
    " EXISTS 패턴: 데이터 전송 없이 존재 여부만 확인 → 최소 비용
    SELECT SINGLE @abap_true
      FROM ZI_SmtWorkCenterCapacity
      WHERE Plant          = @iv_plant
        AND WorkCenterCode = @iv_work_center
      INTO @rv_valid.
  ENDMETHOD.
ENDCLASS.

이 패턴의 포인트는 SELECT SINGLE @abap_true로 존재 여부만 확인해 불필요한 데이터 전송을 없앤 것입니다. 생산 오더 대량 생성 배치에서 작업장별 검증을 수만 번 수행해도 각 호출이 인덱스 접근 수준의 비용으로 끝납니다. 추가로 배치 상황이라면 FOR ALL ENTRIES 대신 WHERE (plant, work_center) IN 범위 테이블로 묶어 호출 횟수 자체를 줄이는 것이 좋습니다.

더 깊이 파고들 주제와 참고 링크

이 글에서 다룬 조회 중심 패턴을 익혔다면, 다음 주제로 확장해 보세요. 능력 소요(Capacity Requirement) 계열 뷰와 결합한 부하율 계산, RAP 기반 작업장 능력 모니터링 Fiori 앱, Analytical 뷰(@Analytics 어노테이션)로 능력 범주별 대시보드 구성, 그리고 Clean Core 원칙에 따른 3-Tier 확장 모델 적용이 자연스러운 다음 단계입니다. CRHD를 직접 읽는 기존 커스텀 코드가 있다면 ATC의 Cloud Readiness 체크로 대상 목록을 뽑아 점진적으로 VDM 뷰로 이관하는 것을 권장합니다.

댓글 0

아직 댓글이 없습니다.