
# ABAP CDS Views ile Performanslı Veri Modelleme: İleri Seviye Mimari Rehberi
SAP projelerinde onlarca kez şu sahneyle karşılaştım: Bir geliştirici, karmaşık bir raporlama ihtiyacını karşılamak için iç içe geçmiş FOR ALL ENTRIES’lerle dolu, 500 satırlık bir ABAP programı yazmış. Performans felaketi, bakımı imkânsız, test edilemez. Oysa aynı ihtiyaç, iyi tasarlanmış birkaç CDS View ile hem daha hızlı hem de çok daha okunabilir şekilde karşılanabilirdi.
Eğer siz de SAP projelerinde veri katmanını daha temiz, daha ölçeklenebilir ve gerçekten performanslı hale getirmek istiyorsanız, bu rehber tam size göre. ABAP CDS Views’i yalnızca temel sözdizimi açısından değil; mimari kararlar, performans tuzakları ve gerçek dünya kullanım senaryoları açısından ele alacağız.
—
## CDS Views Neden Bu Kadar Önemli?
Core Data Services (CDS), SAP’nin HANA veritabanının gücünden tam anlamıyla yararlanmak için tasarladığı veri tanımlama katmanıdır. Klasik ABAP yaklaşımında iş mantığının büyük bir kısmı uygulama sunucusunda (AS ABAP) çalışırdı. CDS ile bu mantığı veritabanı katmanına taşıyabiliriz; yani **code pushdown** prensibini uygulayabiliriz.
Bu fark neden kritik?
– **Ağ trafiğini azaltır**: Veritabanından uygulama sunucusuna taşınan veri miktarı düşer.
– **HANA’nın in-memory gücünden yararlanır**: Aggregation, filtreleme ve join işlemleri çok daha hızlı çalışır.
– **Yeniden kullanılabilir veri modeli**: Bir kez tanımla, onlarca yerde kullan.
– **OData servisleri için hazır**: Fiori uygulamaları doğrudan CDS view’larını tüketebilir.
Anca şunu da açıkça söyleyeyim: CDS Views bir sihir değil. Yanlış kullanıldığında performans sorunlarını çözmek bir yana, daha da kötüleştirebilirsiniz.
—
## CDS View Katman Mimarisi: Nasıl Düşünmeliyiz?
Benim benimsediğim ve projelerimde uyguladığım yaklaşım, CDS katmanlarını net bir şekilde ayırmaktır. Bu; SAP’nin kendi VDM (Virtual Data Model) yaklaşımıyla da örtüşür.
### Katman 1: Basic Interface Views (I_ prefix)
Bu katman, ham veritabanı tablolarını CDS modeline taşır. Burada iş mantığı yoktur; yalnızca temel alan atamaları, annotation’lar ve çok basit dönüşümler bulunur.
abap
@AbapCatalog.sqlViewName: 'ZI_SALESORDER'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Basic View'
define view ZI_SalesOrder
as select from vbak
association [0..1] to ZI_Customer as _Customer
on $projection.SoldToParty = _Customer.Customer
{
key vbak.vbeln as SalesOrder,
vbak.erdat as CreationDate,
vbak.kunnr as SoldToParty,
vbak.netwr as NetValue,
vbak.waerk as DocumentCurrency,
vbak.vkorg as SalesOrganization,
/* Associations */
_Customer
}
**Dikkat edilmesi gereken noktar**: Bu katmanda `WHERE` koşulları minimumda tutun. Filtreleme mantığını üst katmanlara bırakın.
### Katman 2: Composite Interface Views
Birden fazla basic view’u bir araya getirir. Join’ler ve daha karmaşık association’lar bu katmanda yer alır.
abap
@AbapCatalog.sqlViewName: 'ZI_SALESORDERHDR'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Header Composite'
define view ZI_SalesOrderHeader
as select from ZI_SalesOrder as SalesOrder
inner join ZI_Customer as Customer
on SalesOrder.SoldToParty = Customer.Customer
{
key SalesOrder.SalesOrder,
SalesOrder.CreationDate,
SalesOrder.NetValue,
SalesOrder.DocumentCurrency,
Customer.CustomerName,
Customer.Country,
Customer.Region,
/* Currency Conversion */
@Semantics.amount.currencyCode: 'DocumentCurrency'
SalesOrder.NetValue,
currency_conversion(
amount => SalesOrder.NetValue,
source_currency => SalesOrder.DocumentCurrency,
target_currency => cast('EUR' as abap.cuky),
exchange_rate_date => SalesOrder.CreationDate
) as NetValueEUR
}
### Katman 3: Consumption Views (C_ prefix)
Bu katman doğrudan UI veya API tarafından tüketilir. Fiori uygulamaları, OData servisleri ve raporlama araçları bu view'ları kullanır. Annotation'lar burada yoğunlaşır.
abap
@AbapCatalog.sqlViewName: 'ZC_SALESORDERHDR'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Header - Consumption'
@UI.headerInfo: {
typeName: 'Sales Order',
typeNamePlural: 'Sales Orders',
title: { value: 'SalesOrder' }
}
define view ZC_SalesOrderHeader
as select from ZI_SalesOrderHeader
{
@UI.lineItem: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
key SalesOrder,
@UI.lineItem: [{ position: 20 }]
CreationDate,
@UI.lineItem: [{ position: 30 }]
CustomerName,
@UI.lineItem: [{ position: 40 }]
@Semantics.amount.currencyCode: 'DocumentCurrency'
NetValue,
DocumentCurrency,
@UI.lineItem: [{ position: 50 }]
NetValueEUR
}
---
## Performans Tuzakları ve Çözümleri
CDS View yazarken en çok karşılaştığım performans sorunlarını ve çözümlerini paylaşayım.
### Tuzak 1: Association Yerine Gereksiz JOIN Kullanımı
Association'lar, yalnızca kullanıldığında JOIN oluşturur. Eğer bir alanı her zaman göstermiyorsanız, JOIN yerine association tercih edin.
abap
-- KÖTÜ: Her zaman JOIN yapılır
define view ZI_BadExample
as select from vbak
inner join kna1 on vbak.kunnr = kna1.kunnr
{
key vbak.vbeln,
kna1.name1 -- Bu alan sadece bazı senaryolarda kullanılıyor
}
-- İYİ: Sadece gerektiğinde JOIN yapılır
define view ZI_GoodExample
as select from vbak
association [0..1] to kna1 as _Customer
on $projection.SoldToParty = _Customer.kunnr
{
key vbeln as SalesOrder,
kunnr as SoldToParty,
_Customer -- Sadece ihtiyaç duyulduğunda expand edilir
}
### Tuzak 2: CDS View Üzerinde ABAP Filtresi
CDS View’u ABAP kodunda açtıktan sonra filtreleme yapmak, veritabanından gereksiz veri çeker.
abap
" KÖTÜ: Tüm veri çekilip ABAP'ta filtreleniyor
SELECT * FROM zc_salesorderheader INTO TABLE @DATA(lt_orders).
DELETE lt_orders WHERE creationdate < '20240101'. " İYİ: Filtre veritabanına pushdown edilir SELECT * FROM zc_salesorderheader WHERE creationdate >= '20240101'
INTO TABLE @DATA(lt_orders).
### Tuzak 3: Yanlış Cardinality Tanımı
Association cardinality'yi yanlış tanımlamak, hem performansı hem de veri bütünlüğünü etkiler.
abap
-- YANLIŞ: Bir siparişin birden fazla pozisyonu olabilir
association [1] to vbap as _OrderItem -- [1] yerine [1..*] olmalı
on $projection.SalesOrder = _OrderItem.vbeln
-- DOĞRU
association [1..*] to vbap as _OrderItem
on $projection.SalesOrder = _OrderItem.vbeln
---
## İleri Seviye: Analytical CDS Views
Raporlama ve analitik senaryolar için Analytical CDS Views kullanın. Bu view tipi, HANA’nın OLAP motoruyla doğrudan entegre çalışır.
abap
@AbapCatalog.sqlViewName: 'ZA_SALESANALYSIS'
@Analytics.dataCategory: #CUBE
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Analysis Cube'
define view ZA_SalesAnalysis
as select from ZI_SalesOrderHeader
association [0..1] to ZI_SalesOrg as _SalesOrg
on $projection.SalesOrganization = _SalesOrg.SalesOrg
{
-- Dimension Fields
@Analytics.dimension: true
@ObjectModel.foreignKey.association: '_SalesOrg'
SalesOrganization,
@Analytics.dimension: true
Country,
-- Time Dimension
@Analytics.dimension: true
@Semantics.dateTime.referencedTableField: 'CreationDate'
CreationDate,
-- Measure Fields
@Analytics.measure: true
@Aggregation.default: #SUM
@Semantics.amount.currencyCode: 'DocumentCurrency'
NetValue,
@Analytics.measure: true
@Aggregation.default: #SUM
NetValueEUR,
DocumentCurrency,
-- Associations
_SalesOrg
}
---
## Access Control: Güvenliği Unutmayın
CDS Views ile birlikte mutlaka DCL (Data Control Language) dosyaları yazın. Bu, yetkilendirme kontrolünü merkezi ve tutarlı hale getirir.
abap
@MappingRole: true
define role ZI_SalesOrder {
grant
select
on ZI_SalesOrder
where (SalesOrganization) = aspect pfcg_auth(
VKORG, -- Auth object field
'03' -- Activity
);
}
---
## CDS View Test Stratejisi
CDS View’ları test etmek için ABAP Unit Test Framework’ü kullanabilirsiniz. Bu, birçok geliştiricinin atladığı ama kritik bir adım.
abap
CLASS zcl_test_sales_order_cds DEFINITION
FINAL
FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT.
PRIVATE SECTION.
DATA: environment TYPE REF TO if_cds_test_environment.
METHODS:
setup,
teardown,
test_filter_by_sales_org FOR TESTING.
ENDCLASS.
CLASS zcl_test_sales_order_cds IMPLEMENTATION.
METHOD setup.
environment = cl_cds_test_environment=>create(
i_for_entity = 'ZI_SALESORDER'
).
ENDMETHOD.
METHOD teardown.
environment->destroy( ).
ENDMETHOD.
METHOD test_filter_by_sales_org.
" Test verisi hazırla
DATA(lt_vbak) = VALUE vbak_tt(
( vbeln = '0000000001' vkorg = '1000' kunnr = '0000001000' netwr = '5000' )
( vbeln = '0000000002' vkorg = '2000' kunnr = '0000001001' netwr = '3000' )
).
environment->insert_test_data( lt_vbak ).
" CDS view'u test et
SELECT salesorder, salesorganization
FROM zi_salesorder
WHERE salesorganization = '1000'
INTO TABLE @DATA(lt_result).
" Assertion
cl_abap_unit_assert=>assert_equals(
act = lines( lt_result )
exp = 1
msg = 'Yalnızca 1000 satış organizasyonu filtreli sonuç bekleniyor'
).
ENDMETHOD.
ENDCLASS.
---
## Gerçek Dünya: Ne Zaman CDS, Ne Zaman ABAP?
Bu soruyu çok sık alıyorum. Kısa yanıt şu:
| Senaryo | Tercih |
|—|—|
| Aggregation, gruplama, toplama | CDS View |
| Karmaşık iş mantığı, koşullu hesaplamalar | ABAP Class |
| OData servisi için veri | CDS View |
| Dosya okuma/yazma | ABAP |
| Raporlama, dashboard | CDS + Analytical View |
| Workflow, BAdI implementasyonu | ABAP |
| Cross-join, complex join senaryoları | CDS (dikkatli) |
Altın kural: **Veritabanında yapılabileni veritabanında yap; iş mantığını ABAP’ta tutmaya devam et.**
—
## Sonuç ve Sonraki Adımlar
CDS Views, modern SAP geliştirme mimarisinin temel taşlarından biri. Doğru kullanıldığında;
– Performansı dramatik şekilde artırır
– Kod tekrarını azaltır
– Bakım maliyetini düşürür
– Fiori ve API geliştirmesini hızlandırır
Bunun yanı sıra, katmanlı mimariyi korumak, cardinality’yi doğru tanımlamak ve mutlaka access control eklemek kritik.
Bir sonraki adım olarak şunları öneririm:
1. Mevcut projenizdeki en sık kullanılan 3 raporu belirleyin
2. Bu raporları CDS katman mimarisine göre yeniden tasarlayın
3. Basic Interface → Composite Interface → Consumption sırasını takip edin
4. Her view için unit test yazın
CDS Views konusunda daha derinlemesine gitmek isteyenler için bir sonraki makalede **CDS View Extensibility** ve **Custom Fields with CDS** konularını ele alacağım.
—
*Bu konuda sorularınız varsa veya kendi projenizdeki mimari kararlarda görüş almak istiyorsanız, yorumlarda paylaşabilirsiniz. Benzer deneyimler yaşadıysanız topluluğumuzla paylaşın; birlikte öğrenmek her zaman daha güçlüdür.*