I_Product CDS View란 무엇인가
SAP의 Virtual Data Model(VDM)에서 I_Product는 제품 마스터 데이터를 표준화된 방식으로 노출하는 핵심 인터페이스 CDS View입니다.
ABAP CDS(Core Data Services)는 데이터베이스 수준에서 뷰를 정의하고 재사용할 수 있게 해주는 프레임워크로,
SAP S/4HANA에서는 전통적인 테이블 직접 접근 대신 이 VDM 계층을 통해 데이터에 접근하는 것이 권장됩니다.
I_Product의 "I_" 접두어는 "Interface"를 의미하며, 외부 소비를 위한 안정적인 공개 API 역할을 합니다.
이 뷰는 내부적으로 MARA(제품 마스터 일반 데이터)를 중심으로 여러 관련 테이블들을 조인하여 제품에 관한 통합적인 뷰를 제공합니다.
VDM 계층 구조
SAP VDM은 다음 세 가지 계층으로 구성됩니다:
| 계층 | 접두어 | 역할 | 예시 |
|---|---|---|---|
| 기본 뷰 (Basic View) | I_ | 단일 엔티티 표현, 재사용 가능한 빌딩 블록 | I_Product, I_Plant |
| 복합 뷰 (Composite View) | I_ (복합) | 여러 기본 뷰 조합, 도메인 로직 포함 | I_ProductPlant |
| 소비 뷰 (Consumption View) | C_ | 앱/서비스별 맞춤형 뷰, UI/API 노출용 | C_ProductStockSalesDelivery |
I_Product는 기본 뷰이면서 동시에 인터페이스 역할을 하므로,
상위 뷰들이 이 뷰에 안정적으로 의존할 수 있습니다.
SAP는 I_ 뷰의 API를 버전 간에 유지하므로, 커스텀 개발 시 MARA를 직접 사용하는 것보다 안정적입니다.
I_Product가 조인하는 테이블 구조
I_Product는 MARA를 루트 테이블로 하여 다음 테이블들을 조인합니다.
각 테이블이 어떤 정보를 제공하는지 이해하면 필요한 필드를 효율적으로 선택할 수 있습니다.
핵심 조인 테이블 목록
| 테이블 | 설명 | 조인 키 | 주요 필드 |
|---|---|---|---|
MARA |
제품 마스터 일반 데이터 (루트) | MATNR | MTART, MATKL, MEINS, BRGEW, NTGEW |
MAKT |
제품 설명 (언어별) | MATNR + SPRAS | MAKTX (단축 설명), MAKTG (긴 설명) |
MARC |
플랜트별 제품 데이터 | MATNR + WERKS | PSTAT, MMSTA, DISMM, DZEIT, EISBE |
MBEW |
재고 평가 데이터 | MATNR + BWKEY | STPRS, VERPR, PEINH, BKLAS, VPRSV |
MVKE |
판매 조직별 제품 데이터 | MATNR + VKORG + VTWEG | MTPOS, KONDM, PROVG, KTGRM |
MLAN |
세금 분류 데이터 | MATNR + ALAND + TATY1 | TAXM1 (세금 분류 코드) |
T001W |
플랜트 마스터 | WERKS | NAME1, ORT01, LAND1 |
I_Product CDS View DDL 구조 예시
실제 SAP 시스템의 I_Product는 내부적으로 다음과 유사한 구조를 가집니다.
(실제 구현은 SAP 버전에 따라 다를 수 있으며, 아래는 개념 설명을 위한 예시입니다.)
@AbapCatalog.sqlViewName: 'IPRODUCT'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Product - Basic Data'
@VDM.viewType: #BASIC
@ObjectModel.usageType:{
serviceQuality: #A,
sizeCategory: #XL,
dataClass: #MASTER
}
define view I_Product
as select from mara
association [0..*] to I_ProductText as _ProductText
on $projection.Product = _ProductText.Product
association [0..*] to I_ProductPlant as _ProductPlant
on $projection.Product = _ProductPlant.Product
association [0..*] to I_ProductValuationJA as _ProductValuation
on $projection.Product = _ProductValuation.Product
{
key mara.matnr as Product,
mara.mtart as ProductType,
mara.matkl as ProductGroup,
mara.meins as BaseUnit,
mara.brgew as GrossWeight,
mara.ntgew as NetWeight,
mara.gewei as WeightUnit,
mara.volum as Volume,
mara.voleh as VolumeUnit,
mara.ean11 as InternationalArticleNumber,
mara.mstae as CrossPlantProductStatus,
mara.mstde as CrossPlantProductStatusValidFrom,
mara.normt as IndustrySector,
mara.laeng as ProductLength,
mara.breit as ProductWidth,
mara.hoehe as ProductHeight,
mara.meabm as SizeOrDimensionUnit,
mara.ernam as CreatedByUser,
mara.ersda as CreationDate,
mara.aenam as LastChangedByUser,
mara.aedat as LastChangeDate,
/* Associations */
_ProductText,
_ProductPlant,
_ProductValuation
}
I_ProductText 뷰 (MAKT 기반)
@AbapCatalog.sqlViewName: 'IPRODUCTTEXT'
@VDM.viewType: #BASIC
@ObjectModel.dataCategory: #TEXT
define view I_ProductText
as select from makt
{
key matnr as Product,
key spras as Language,
maktx as ProductDescription,
maktg as ProductExternalDescription
}
ABAP에서 I_Product 활용하기
I_Product를 활용하는 방법은 크게 세 가지입니다:
Open SQL로 직접 SELECT, CDS Association을 통한 관련 데이터 조회, ABAP RESTful Application Programming(RAP) 모델에서의 활용.
예시 1: 기본 제품 정보 조회
*&---------------------------------------------------------------------*
*& 기본 제품 정보 조회 - I_Product 직접 SELECT
*&---------------------------------------------------------------------*
DATA: lt_products TYPE TABLE OF ZPRODUCT_INFO,
ls_product LIKE LINE OF lt_products.
DATA: BEGIN OF ls_result,
product TYPE i_product-product,
producttype TYPE i_product-producttype,
productgroup TYPE i_product-productgroup,
baseunit TYPE i_product-baseunit,
grossweight TYPE i_product-grossweight,
weightunit TYPE i_product-weightunit,
lastchangedate TYPE i_product-lastchangedate,
END OF ls_result.
DATA: lt_results LIKE TABLE OF ls_result.
SELECT product,
producttype,
productgroup,
baseunit,
grossweight,
weightunit,
lastchangedate
FROM i_product
WHERE producttype = 'FERT' " 완성품만
AND crossplantproductstatus = '' " 유효한 제품만
ORDER BY product
INTO TABLE @lt_results.
LOOP AT lt_results INTO ls_result.
WRITE: / ls_result-product,
ls_result-producttype,
ls_result-baseunit,
ls_result-grossweight,
ls_result-weightunit.
ENDLOOP.
예시 2: 제품 설명 포함 조회 (Association 활용)
*&---------------------------------------------------------------------*
*& 제품 + 설명 조인 조회 - Association 활용
*& I_ProductText는 I_Product의 _ProductText Association
*&---------------------------------------------------------------------*
DATA: BEGIN OF ls_product_with_text,
product TYPE c LENGTH 40,
producttype TYPE c LENGTH 4,
productgroup TYPE c LENGTH 9,
productdescription TYPE c LENGTH 40,
language TYPE c LENGTH 2,
END OF ls_product_with_text.
DATA: lt_products_text LIKE TABLE OF ls_product_with_text.
" Association을 통한 텍스트 조인 (언어별)
SELECT p~product,
p~producttype,
p~productgroup,
t~productdescription,
t~language
FROM i_product AS p
JOIN i_producttext AS t
ON p~product = t~product
AND t~language = @sy-langu
WHERE p~productgroup IN ('MAT01', 'MAT02', 'MAT03')
AND p~producttype <> 'DIEN' " 서비스 제품 제외
ORDER BY p~product
INTO TABLE @lt_products_text.
IF sy-subrc = 0.
LOOP AT lt_products_text INTO ls_product_with_text.
WRITE: / ls_product_with_text-product,
ls_product_with_text-productdescription.
ENDLOOP.
ELSE.
MESSAGE '조회된 제품이 없습니다.' TYPE 'I'.
ENDIF.
예시 3: 재고 평가 데이터와 결합 조회
*&---------------------------------------------------------------------*
*& 제품 + 재고평가(MBEW) 통합 조회
*& 구매 표준가 또는 이동평균가 확인
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_product_valuation,
product TYPE mara-matnr,
productdesc TYPE makt-maktx,
valuationarea TYPE mbew-bwkey,
pricectrlind TYPE mbew-vprsv, " S=표준가, V=이동평균가
standardprice TYPE mbew-stprs,
movavgprice TYPE mbew-verpr,
priceunit TYPE mbew-peinh,
valuationclass TYPE mbew-bklas,
END OF ty_product_valuation.
DATA: lt_val TYPE TABLE OF ty_product_valuation.
" MBEW 기반 I_ProductValuation 뷰 활용
" (실제 시스템에서는 I_ProductValuationJA 또는 유사 뷰 사용)
SELECT p~matnr AS product,
t~maktx AS productdesc,
v~bwkey AS valuationarea,
v~vprsv AS pricectrlind,
v~stprs AS standardprice,
v~verpr AS movavgprice,
v~peinh AS priceunit,
v~bklas AS valuationclass
FROM mara AS p
JOIN makt AS t ON p~matnr = t~matnr AND t~spras = @sy-langu
JOIN mbew AS v ON p~matnr = v~matnr AND v~bwkey = @lv_plant
WHERE p~mtart = 'ROH' " 원자재만
AND v~vprsv = 'S' " 표준가 관리 품목만
AND v~stprs > 0 " 표준가 등록된 품목만
ORDER BY p~matnr
INTO TABLE @lt_val.
" 조회 결과 처리
LOOP AT lt_val INTO DATA(ls_val).
" 표준가와 이동평균가 비교 분석 로직
IF ls_val-pricectrlind = 'S'.
WRITE: / ls_val-product, '표준가:', ls_val-standardprice, ls_val-priceunit.
ENDIF.
ENDLOOP.
실무 활용 시나리오
시나리오 1: 제품 마스터 검증 리포트
신규 제품 등록 후 필수 데이터 완성도 검증이 필요한 경우,
I_Product와 관련 뷰를 활용하여 누락 데이터를 확인할 수 있습니다.
*&---------------------------------------------------------------------*
*& 제품 마스터 데이터 완성도 검증
*& - 설명 누락, 중량 미입력, 제품군 미지정 등 체크
*&---------------------------------------------------------------------*
DATA: BEGIN OF ls_incomplete,
product TYPE mara-matnr,
issue_type TYPE c LENGTH 50,
END OF ls_incomplete.
DATA: lt_incomplete LIKE TABLE OF ls_incomplete.
" 설명 누락 제품 확인
SELECT p~product
FROM i_product AS p
WHERE NOT EXISTS (
SELECT 1 FROM i_producttext AS t
WHERE t~product = p~product
AND t~language = 'KO'
)
AND p~lastchangedate > @lv_from_date
INTO TABLE @DATA(lt_no_desc).
LOOP AT lt_no_desc INTO DATA(ls_prod).
ls_incomplete-product = ls_prod-product.
ls_incomplete-issue_type = '한국어 제품 설명 누락'.
APPEND ls_incomplete TO lt_incomplete.
ENDLOOP.
" 중량 미입력 완성품 확인
SELECT product
FROM i_product
WHERE producttype = 'FERT'
AND ( grossweight = 0 OR netweight = 0 )
INTO TABLE @DATA(lt_no_weight).
LOOP AT lt_no_weight INTO DATA(ls_w).
ls_incomplete-product = ls_w-product.
ls_incomplete-issue_type = '완성품 중량 정보 미입력'.
APPEND ls_incomplete TO lt_incomplete.
ENDLOOP.
" 결과 출력
LOOP AT lt_incomplete INTO ls_incomplete.
WRITE: / ls_incomplete-product, ls_incomplete-issue_type.
ENDLOOP.
시나리오 2: OData 서비스에서 I_Product 노출
RAP(RESTful ABAP Programming) 모델을 사용하면 I_Product를 기반으로
OData V4 서비스를 빠르게 구성할 수 있습니다.
소비 뷰(C_)를 생성할 때 I_Product를 기반으로 필요한 필드만 선택하는 방식을 권장합니다.
@AbapCatalog.sqlViewName: 'ZPRODCATALOG'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '제품 카탈로그 소비 뷰'
@VDM.viewType: #CONSUMPTION
@OData.publish: true
define view ZC_ProductCatalog
as select from I_Product as prod
association [0..*] to I_ProductText as _text
on $projection.Product = _text.Product
and _text.Language = $session.system_language
{
key prod.Product,
prod.ProductType,
prod.ProductGroup,
prod.BaseUnit,
prod.GrossWeight,
prod.NetWeight,
prod.WeightUnit,
prod.LastChangeDate,
_text.ProductDescription,
/* Navigation */
_text
}
where prod.ProductType <> 'DIEN'
성능 고려사항과 주의점
필드 선택 최적화
I_Product는 내부적으로 여러 테이블을 조인하므로,
SELECT * 사용은 피하고 필요한 필드만 명시적으로 선택해야 합니다.
특히 MAKT(텍스트), MBEW(평가), MVKE(판매) 데이터가 필요 없는 경우,
해당 Association을 통해 접근하지 않으면 조인이 발생하지 않습니다.
- 필요한 필드만 SELECT 절에 명시 (SELECT *는 지양)
- WHERE 절에 인덱스 필드(MATNR, MTART, MATKL) 활용
- 텍스트 조인 시 반드시 언어 조건(SPRAS = sy-langu) 추가
- 대량 조회 시 PACKAGE SIZE와 함께 CURSOR 방식 고려
- CDS View에 정의된 @AccessControl을 통해 권한 자동 적용됨을 인지
접근 권한 (Authorization Check)
I_Product는 @AccessControl.authorizationCheck: #CHECK 설정으로
CDS Access Control(DCL)을 통해 권한을 자동으로 검증합니다.
즉, 사용자가 접근 권한이 없는 제품 데이터는 자동으로 필터링되므로,
별도의 권한 체크 로직을 추가할 필요가 없습니다.
이것이 MARA 직접 접근 대신 I_Product를 사용해야 하는 중요한 이유 중 하나입니다.
커스텀 개발 시 권장 패턴
- 확장(Extension): I_Product를 직접 수정하지 말고, 커스텀 소비 뷰(ZC_)를 생성하여 래핑
- Association 활용: 필요한 관련 데이터는 Association으로 Lazy Loading 방식 접근
- 캐싱 고려: 반복 조회되는 제품 마스터는 버퍼링 또는 인메모리 테이블 활용
- 버전 안정성: I_ 뷰는 SAP가 하위 호환성을 보장하므로 업그레이드 영향 최소화
MARA 직접 접근 vs I_Product 사용 비교
| 구분 | MARA 직접 접근 | I_Product 활용 |
|---|---|---|
| 권한 체크 | 수동으로 AUTHORITY-CHECK 필요 | DCL에 의해 자동 적용 |
| 업그레이드 안정성 | 테이블 구조 변경 시 영향받음 | SAP가 API 호환성 보장 |
| 데이터 통합 | 관련 테이블 수동 조인 필요 | Association으로 선언적 조인 |
| 성능 | 최적화된 직접 쿼리 가능 | VDM 오버헤드 있으나 HANA 최적화 |
| 유지보수 | 변경 시 모든 참조 코드 수정 필요 | 중앙 집중식 변경 반영 |
| 표준 준수 | 비권장 (레거시 방식) | SAP S/4HANA 표준 방식 |
SAP S/4HANA 환경에서는 I_Product를 통한 접근이 권장되는 표준 방식입니다.
MARA를 직접 참조하는 레거시 코드가 있다면, 점진적으로 I_Product 기반으로 전환하는 것이
장기적인 유지보수성과 시스템 업그레이드 안정성 측면에서 유리합니다.
댓글 0
아직 댓글이 없습니다.