# ABAP CDS Views ile Performanslı Veri Modelleme: Mimari Perspektiften Kapsamlı Rehber
SAP sistemlerinde yıllar içinde onlarca farklı raporlama katmanı gördüm—Open SQL sorguları, klasik views, BAPI’lar ve en sonunda CDS Views. Dürüst olmak gerekirse, CDS Views’ın sisteme girdiği günden bu yana veri modelleme yaklaşımım köklü biçimde değişti. Eğer hâlâ veritabanı tablolarını doğrudan SELECT ile sorguluyorsanız ya da klasik Database Views kullanıyorsanız, bu makale tam size göre.
Bu rehberde ABAP CDS Views’ı sadece teorik düzeyde değil, gerçek projelerde karşılaştığım sorunlar ve geliştirdiğim çözüm kalıpları üzerinden ele alacağım. Sonunda elinizde çalışan kod örnekleri, mimari karar kriterleri ve production’a taşıyabileceğiniz best practices olacak.
—
## CDS Views Nedir ve Neden Önemli?
**Core Data Services (CDS)**, SAP HANA ile birlikte hayatımıza giren ve veritabanı katmanına yakın, semantik açıdan zengin veri modelleri tanımlamanıza olanak tanıyan bir çerçevedir. ABAP CDS ise bu çerçevenin ABAP Development Tools (ADT) üzerinden kullanılan versiyonudur.
Klasik yaklaşımda şöyle bir kod yazardık:
abap
” Eski Yöntem – Kaçınılması Gereken
SELECT vbak~vbeln,
vbak~erdat,
vbap~matnr,
vbap~kwmeng,
mara~maktx
FROM vbak
JOIN vbap ON vbak~vbeln = vbap~vbeln
JOIN makt ON vbap~matnr = makt~matnr
AND makt~spras = sy-langu
INTO TABLE @DATA(lt_orders)
WHERE vbak~erdat >= @lv_date_from.
Bu yaklaşımın sorunları:
– **Tekrar eden kod**: Aynı JOIN mantığını onlarca raporda yazarsınız
– **Bakım yükü**: Bir alan değiştiğinde tüm programları güncellemek gerekir
– **Pushdown yok**: İş mantığı ABAP katmanında çalışır, HANA’nın gücünden yararlanılmaz
– **Semantik yok**: OData, Fiori gibi katmanlarla entegrasyon zorlaşır
CDS Views bu sorunların tamamını elegant biçimde çözer.
—
## CDS View Türleri: Hangisini Ne Zaman Kullanmalısınız?
Mimari kararlar arasında en sık karıştırılanı CDS view tiplerinin seçimidir. Üç temel tip vardır:
### 1. Basic Interface View (I_ prefix)
Bu katman, ham veritabanı tablolarını semantic bir modele dönüştürür. Yeniden kullanılabilirliğin temeli burada atılır.
cds
@AbapCatalog.sqlViewName: ‘ZVSALESORDER’
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: ‘Sales Order Basic View’
define view ZI_SalesOrder
as select from vbak
association [0..*] to ZI_SalesOrderItem as _Item
on $projection.SalesOrder = _Item.SalesOrder
{
@Semantics.businessObject.role: #ORDER
key vbeln as SalesOrder,
@Semantics.user.createdBy: true
ernam as CreatedByUser,
@Semantics.systemDate.createdAt: true
erdat as CreationDate,
auart as SalesOrderType,
kunnr as SoldToParty,
netwr as NetAmount,
@Semantics.currencyCode: true
waerk as TransactionCurrency,
/* Association yayınlama */
_Item
}
**Kritik nokta**: Basic interface views’da iş mantığı **olmaz**. Sadece alan isimlendirme, tip dönüşümü ve association tanımları yapılır.
### 2. Composite Interface View (I_ prefix, birden fazla kaynak)
Birden fazla basic view’ı birleştiren, iş mantığı eklemeye başladığınız katmandır.
cds
@AbapCatalog.sqlViewName: ‘ZVSALESORDEXT’
@EndUserText.label: ‘Sales Order with Customer Data’
define view ZI_SalesOrderExtended
as select from ZI_SalesOrder as SalesOrder
left outer join I_Customer as Customer
on SalesOrder.SoldToParty = Customer.Customer
{
key SalesOrder.SalesOrder,
SalesOrder.CreationDate,
SalesOrder.SalesOrderType,
SalesOrder.NetAmount,
SalesOrder.TransactionCurrency,
Customer.CustomerName,
Customer.Country,
Customer.Region,
/* Hesaplamalı alan – HANA’da çalışır */
case
when SalesOrder.NetAmount >= 10000 then ‘A’
when SalesOrder.NetAmount >= 5000 then ‘B’
else ‘C’
end as CustomerSegment,
/* Koşullu birleştirme */
concat(Customer.CustomerName, ‘ – ‘, Customer.Country)
as CustomerDisplay
}
### 3. Consumption View (C_ prefix)
Son kullanıcıya veya dış sistemlere (OData, Fiori) açılan katmandır. Burada UI annotasyonları, filtre gereksinimleri ve yetkilendirme kontrolü ön plana çıkar.
cds
@AbapCatalog.sqlViewName: ‘ZVCSALESORD’
@EndUserText.label: ‘Sales Order Consumption View’
@UI.headerInfo: {
typeName: ‘Sales Order’,
typeNamePlural: ‘Sales Orders’,
title: { type: #STANDARD, value: ‘SalesOrder’ }
}
define view ZC_SalesOrder
as select from ZI_SalesOrderExtended
{
@UI.facet: [{
id: ‘GeneralInfo’,
type: #COLLECTION,
label: ‘General Information’,
position: 1
}]
@UI.lineItem: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
key SalesOrder,
@UI.lineItem: [{ position: 20 }]
@UI.selectionField: [{ position: 20 }]
CreationDate,
@UI.lineItem: [{ position: 30 }]
CustomerName,
@UI.lineItem: [{ position: 40, criticality: ‘CustomerSegmentCriticality’ }]
CustomerSegment,
@UI.hidden: true
case CustomerSegment
when ‘A’ then 3 ” Yeşil
when ‘B’ then 2 ” Sarı
else 1 ” Kırmızı
end as CustomerSegmentCriticality,
NetAmount,
TransactionCurrency
}
—
## Performans Optimizasyonu: HANA Pushdown’ın Gücü
CDS Views’ın en kritik avantajı, hesaplamaları veritabanı katmanına taşıyabilmesidir. Buna **HANA Pushdown** diyoruz ve doğru kullanıldığında performans farkı dramatik olabilir.
### Aggregation Pushdown
cds
@AbapCatalog.sqlViewName: ‘ZVORDERSUMM’
@EndUserText.label: ‘Sales Order Summary by Customer’
define view ZI_SalesOrderSummary
as select from ZI_SalesOrderExtended
{
SoldToParty,
CustomerName,
Country,
@DefaultAggregation: #SUM
@Semantics.amount.currencyCode: ‘TransactionCurrency’
sum(NetAmount) as TotalNetAmount,
@DefaultAggregation: #COUNT_DISTINCT
count(distinct SalesOrder) as OrderCount,
@DefaultAggregation: #AVG
@Semantics.amount.currencyCode: ‘TransactionCurrency’
avg(NetAmount) as AverageOrderValue,
TransactionCurrency
}
group by
SoldToParty,
CustomerName,
Country,
TransactionCurrency
Bu view’ı ABAP’ta şöyle kullanırsınız:
abap
” Temiz, okunabilir ve HANA’da çalışan sorgu
SELECT *
FROM zi_salesordersummary
WHERE country = ‘TR’
AND totalnetamount > 50000
ORDER BY totalnetamount DESCENDING
INTO TABLE @DATA(lt_summary).
” Sonuçları işle
LOOP AT lt_summary INTO DATA(ls_summary).
WRITE: / ls_summary-customername,
ls_summary-ordercount,
ls_summary-totalnetamount.
ENDLOOP.
### Window Functions ile İleri Analitik
SAP HANA’nın window function desteği, CDS üzerinden kullanılabilir:
cds
@AbapCatalog.sqlViewName: ‘ZVORDERRANK’
@EndUserText.label: ‘Sales Order Ranking’
define view ZI_SalesOrderRanking
as select from ZI_SalesOrderSummary
{
SoldToParty,
CustomerName,
TotalNetAmount,
OrderCount,
TransactionCurrency,
/** Ülke bazlı sıralama – HANA Window Function */
rank() over(
partition by TransactionCurrency
order by TotalNetAmount descending
) as RevenueRank,
/** Kümülatif toplam */
sum(TotalNetAmount) over(
partition by TransactionCurrency
order by TotalNetAmount descending
rows between unbounded preceding and current row
) as CumulativeRevenue
}
—
## Yetkilendirme Kontrolü: DCL ile Veri Güvenliği
CDS Views’ın göz ardı edilen ama kritik özelliklerinden biri **Data Control Language (DCL)** desteğidir. Performans optimizasyonu kadar önemli bir konudur.
cds
” ZI_SalesOrder.dcls dosyası
@MappingRole: true
define role ZI_SalesOrder {
grant select on ZI_SalesOrder
where (SalesOrg) = aspect pfcg_auth(V_VBAK_VKO, VKORG, ACTVT = ’03’);
}
Bu tanımla, kullanıcı yalnızca yetkili olduğu satış organizasyonlarına ait siparişleri görebilir. Yetkilendirme kontrolü otomatik olarak HANA katmanında yapılır—ABAP kodunuzda `AUTHORITY-CHECK` yazmaya gerek kalmaz.
—
## Pratik Mimari Karar Rehberi
Projelerde sıkça sorulan soru: **”Ne zaman CDS View, ne zaman ABAP programı kullanmalıyım?”**
| Senaryo | Öneri | Gerekçe |
|—|—|—|
| Raporlama / Analitik | CDS View | HANA pushdown, Fiori uyumu |
| Veri okuma (basit JOIN) | CDS View | Tekrar kullanılabilirlik |
| Karmaşık iş mantığı | ABAP Class + CDS | Separation of concerns |
| Veri yazma / güncelleme | ABAP / BOPF | CDS okuma odaklı |
| OData servisi | CDS + @OData | Native entegrasyon |
| Gerçek zamanlı hesaplama | CDS + AMDP | HANA Native |
—
## AMDP ile Hybrid Yaklaşım
Bazen CDS tek başına yeterli olmaz. Karmaşık algoritmik hesaplamalar için **ABAP Managed Database Procedures (AMDP)** CDS ile birlikte kullanılabilir:
abap
CLASS zcl_sales_analytics DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
CLASS-METHODS get_top_customers
IMPORTING
VALUE(iv_min_revenue) TYPE netwr_fp
VALUE(iv_top_n) TYPE i
EXPORTING
VALUE(et_customers) TYPE STANDARD TABLE OF zst_customer_rank
RAISING
cx_amdp_error.
ENDCLASS.
CLASS zcl_sales_analytics IMPLEMENTATION.
METHOD get_top_customers
BY DATABASE PROCEDURE FOR HDB
LANGUAGE SQLSCRIPT
USING zi_salesordersummary.
— HANA SQLScript – Doğrudan HANA’da çalışır
et_customers = SELECT
soldtoparty,
customername,
totalnetamount,
ordercount,
RANK() OVER (ORDER BY totalnetamount DESC) as rank
FROM “ZI_SALESORDERSUMMARY”
WHERE totalnetamount >= :iv_min_revenue
ORDER BY totalnetamount DESC
LIMIT :iv_top_n;
ENDMETHOD.
ENDCLASS.
Bu yaklaşım, CDS’nin semantik katmanını korurken HANA’nın tam performansından yararlanmanızı sağlar.
—
## Sık Yapılan Hatalar ve Çözümleri
Yıllarca CDS projelerinde gördüğüm en yaygın hatalar:
**1. View içinde view içinde view (aşırı nesting)**
Çözüm: Üçten fazla katman oluşturmaktan kaçının. Gerekirse AMDP veya orta katman tablo kullanın.
**2. Consumption view’da iş mantığı**
Çözüm: UI annotasyonları dışındaki mantığı interface view’a taşıyın. C_ prefix = UI katmanı.
**3. @AccessControl.authorizationCheck: #NOT_REQUIRED kullanımı**
Çözüm: Development’ta bile `#CHECK` veya `#PRIVILEGED_ONLY` kullanın. Production’da güvenlik açığı oluşturur.
**4. Association yerine JOIN kullanımı**
Çözüm: Associations lazy loading sağlar—sadece kullanıldığında JOIN yapılır. Bu büyük performans farkı yaratır.
cds
” Yanlış – Her zaman JOIN yapılır
define view ZI_BadExample
as select from vbak
join vbap on vbak.vbeln = vbap.vbeln
join makt on vbap.matnr = makt.matnr
{ … }
” Doğru – Association ile lazy loading
define view ZI_GoodExample
as select from vbak
association [0..*] to ZI_SalesOrderItem as _Item
on $projection.SalesOrder = _Item.SalesOrder
{ key vbeln as SalesOrder, _Item }
—
## Unit Test: CDS Views Nasıl Test Edilir?
CDS Views’ın test edilebilirliği sıkça atlanır. ABAP Unit Test çerçevesi ile mock data kullanarak test yapabilirsiniz:
abap
CLASS ztcl_sales_order_view DEFINITION
FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
PRIVATE SECTION.
DATA: mo_environment TYPE REF TO if_cds_test_environment.
METHODS:
setup,
teardown,
test_customer_segment FOR TESTING.
ENDCLASS.
CLASS ztcl_sales_order_view IMPLEMENTATION.
METHOD setup.
” CDS test ortamı oluştur
mo_environment = cl_cds_test_environment=>create(
i_for_entity = ‘ZI_SALESORDEREXTENDED’
).
ENDMETHOD.
METHOD test_customer_segment.
” Test verisi hazırla
DATA(lt_test_data) = VALUE zt_salesorder(
( salesorder = ‘0000000001’ netamount = 15000 transactioncurrency = ‘EUR’ )
( salesorder = ‘0000000002’ netamount = 7500 transactioncurrency = ‘EUR’ )
( salesorder = ‘0000000003’ netamount = 1000 transactioncurrency = ‘EUR’ )
).
” Mock data enjekte et
mo_environment->insert_test_data( i_data = lt_test_data ).
” CDS view’ı sorgula
SELECT salesorder, customersegment
FROM zi_salesorderextended
INTO TABLE @DATA(lt_result).
” Segment kontrolü
cl_abap_unit_assert=>assert_equals(
exp = ‘A’
act = lt_result[ salesorder = ‘0000000001’ ]-customersegment
msg = ‘High value order should be segment A’
).
ENDMETHOD.
METHOD teardown.
mo_environment->destroy( ).
ENDMETHOD.
ENDCLASS.
—
## Sonuç: CDS Views Sadece Bir Araç Değil, Bir Mimari Karar
CDS Views’ı benimsemek, salt teknik bir geçiş değil—veri modelleme felsefenizin değişmesi demektir. Şu temel prensipleri aklınızda tutun:
– **Katmanlı mimari**: I_ (Basic) → I_ (Composite) → C_ (Consumption) hiyerarşisine sadık kalın
– **HANA’yı kullanın**: Hesaplamaları ABAP’ta değil, veritabanı katmanında yapın
– **Association > JOIN**: Lazy loading’in performans avantajını kesinlikle kullanın
– **DCL’i atlama**: Yetkilendirme kontrolü mimari kararın parçasıdır, sonradan eklenen bir şey değil
– **Test yazın**: CDS Test Environment çerçevesi bu iş için tasarlanmıştır
Bir projeyi baştan CDS ile tasarlamak ile mevcut kodu CDS’e taşımak çok farklı deneyimler. Eğer legacy bir sistemdeyseniz, tüm sistemi bir anda dönüştürmeye çalışmayın. Yeni raporlar ve Fiori uygulamaları için CDS’i başlangıç noktası yapın, eski kodları fırsat buldukça dönüştürün.
Sonraki adım olarak **CDS-based OData V4 servis oluşturmayı** incelemenizi tavsiye ederim—bu konuyu yakında ayrı bir makalede detaylı ele alacağım.
—
*Bu makale faydalı olduysa, SAP geliştirme süreçlerinde benzer sorunlar yaşayan ekip arkadaşlarınızla paylaşmayı unutmayın. CDS Views ile ilgili projelerinizde karşılaştığınız zorlu senaryoları yorumlarda paylaşabilirsiniz—gerçek dünya problemleri üzerinden konuşmak her zaman daha öğretici olur.*