ABAP CDS Views Serisi 2: Association ve Join Stratejileri
ABAP

ABAP CDS Views Serisi 2: Association ve Join Stratejileri

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.