Skillquality 0.46

cds-view-entities

Help with CDS (Core Data Services) view entity development including data modeling, annotations, associations, compositions, access controls, aggregate expressions, built-in functions, and input parameters. Use when users ask about CDS views, CDS view entities, CDS annotations, C

Price
free
Protocol
skill
Verified
no

What it does

CDS View Entities

Guide for building semantic data models using ABAP CDS (Core Data Services) view entities in ABAP Cloud.

Workflow

  1. Determine the user's goal:

    • Creating a new data model (standalone or for RAP)
    • Defining relationships between entities (associations, compositions)
    • Adding annotations for UI, semantics, or analytics
    • Implementing access controls
    • Using expressions, functions, or parameters in CDS
  2. Identify the context:

    • Standalone CDS view vs. RAP BO data model
    • Root entity vs. child entity vs. projection view
    • Transactional (RAP) vs. analytical vs. read-only consumption
  3. Apply best practices:

    • Use CDS view entities (v2 syntax define view entity) — not legacy CDS views (define view)
    • Follow naming conventions (e.g., ZR_* for interface/BO views, ZC_* for consumption/projection views, ZI_* for reuse views)
    • Add appropriate annotations for metadata consumers (UI, OData, analytics)

CDS View Entity Syntax

Basic View Entity

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order'
define view entity ZI_SalesOrder
  as select from zsalesorder
{
  key order_id       as OrderId,
      customer_id    as CustomerId,
      order_date     as OrderDate,
      net_amount     as NetAmount,
      currency_code  as CurrencyCode,
      status         as Status,
      created_by     as CreatedBy,
      created_at     as CreatedAt,
      last_changed_at as LastChangedAt
}

Root View Entity (for RAP)

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Root'
define root view entity ZR_SalesOrder
  as select from zsalesorder
  composition [0..*] of ZR_SalesOrderItem as _Item
{
  key order_uuid         as OrderUUID,
      order_id           as OrderId,
      customer_id        as CustomerId,
      order_date         as OrderDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      net_amount         as NetAmount,
      currency_code      as CurrencyCode,
      status             as Status,

      @Semantics.user.createdBy: true
      created_by         as CreatedBy,
      @Semantics.systemDateTime.createdAt: true
      created_at         as CreatedAt,
      @Semantics.user.localInstanceLastChangedBy: true
      last_changed_by    as LastChangedBy,
      @Semantics.systemDateTime.localInstanceLastChangedAt: true
      last_changed_at    as LastChangedAt,
      @Semantics.systemDateTime.lastChangedAt: true
      last_changed_at    as LastChangedAt,

      _Item
}

Child View Entity

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Item'
define view entity ZR_SalesOrderItem
  as select from zsalesorder_item
  association to parent ZR_SalesOrder as _Order
    on $projection.OrderUUID = _Order.OrderUUID
{
  key item_uuid       as ItemUUID,
      order_uuid      as OrderUUID,
      product_id      as ProductId,
      quantity         as Quantity,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      unit_price       as UnitPrice,
      currency_code    as CurrencyCode,

      @Semantics.user.createdBy: true
      created_by       as CreatedBy,
      @Semantics.systemDateTime.localInstanceLastChangedAt: true
      last_changed_at  as LastChangedAt,

      _Order
}

Projection View (Consumption Layer)

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Projection'
@Metadata.allowExtensions: true
define view entity ZC_SalesOrder
  as projection on ZR_SalesOrder
{
  key OrderUUID,
      OrderId,
      CustomerId,
      OrderDate,
      NetAmount,
      CurrencyCode,
      Status,
      CreatedBy,
      CreatedAt,
      LastChangedBy,
      LastChangedAt,

      _Item : redirected to composition child ZC_SalesOrderItem
}

Associations & Compositions

Association Types

TypeSyntaxUse Case
Regular associationassociation [0..1] to ZI_Customer as _Customer on ...Independent entities (e.g., master data lookup)
Compositioncomposition [0..*] of ZR_Child as _ChildParent-child with lifecycle dependency (RAP BO trees)
To-parent associationassociation to parent ZR_Parent as _Parent on ...Child → parent back-reference in compositions

Association Syntax

define view entity ZI_SalesOrder
  as select from zsalesorder
  association [0..1] to ZI_Customer as _Customer
    on $projection.CustomerId = _Customer.CustomerId
  association [0..*] to ZI_SalesOrderItem as _Item
    on $projection.OrderId = _Item.OrderId
{
  key order_id    as OrderId,
      customer_id as CustomerId,

      // Expose associations — required for consumption via ABAP SQL or OData
      _Customer,
      _Item
}

Using Associations in ABAP SQL

" Path expression — triggers LEFT OUTER JOIN by default
SELECT FROM zi_salesorder
  FIELDS OrderId,
         \_Customer-CustomerName,
         \_Item-ProductId
  WHERE OrderId = @lv_order_id
  INTO TABLE @DATA(lt_result).

" Filtering associations
SELECT FROM zi_salesorder
  FIELDS OrderId, \_Item[ ProductId = 'PROD01' ]-Quantity
  WHERE OrderId = @lv_order_id
  INTO TABLE @DATA(lt_filtered).

Expressions & Built-in Functions

Cast Expressions

cast( amount as abap.dec(15,2) ) as ConvertedAmount,
cast( status as abap.char(10) )  as StatusText,

Case Expressions

// Simple CASE
case status
  when 'N' then 'New'
  when 'A' then 'Approved'
  when 'R' then 'Rejected'
  else 'Unknown'
end as StatusText,

// Searched CASE
case when net_amount > 10000 then 'High'
     when net_amount > 1000  then 'Medium'
     else 'Low'
end as PriorityCategory,

Arithmetic Expressions

quantity * unit_price as TotalPrice,
net_amount + tax_amount as GrossAmount,

String Functions

concat( first_name, concat( ' ', last_name ) ) as FullName,
substring( postal_code, 1, 2 )                 as Region,
length( description )                          as DescLength,
upper( country_code )                          as CountryUpper,

Date & Time Functions

dats_days_between( start_date, end_date ) as DurationDays,
dats_add_days( order_date, 30 )           as DueDate,
tstmp_current_utctimestamp()              as CurrentTimestamp,

Aggregate Expressions

define view entity ZI_OrderSummary
  as select from zsalesorder
{
  key customer_id as CustomerId,
      count(*)                      as OrderCount,
      sum( net_amount )             as TotalAmount,
      avg( net_amount as abap.dec(15,2) ) as AvgAmount,
      min( order_date )             as FirstOrderDate,
      max( order_date )             as LastOrderDate
}
group by customer_id

Input Parameters

define view entity ZI_SalesOrderByDate
  with parameters
    p_date : abap.dats
  as select from zsalesorder
{
  key order_id   as OrderId,
      order_date as OrderDate,
      net_amount as NetAmount
}
where order_date >= $parameters.p_date

Using in ABAP SQL:

SELECT FROM zi_salesorderbydate( p_date = @lv_date )
  FIELDS OrderId, OrderDate, NetAmount
  INTO TABLE @DATA(lt_orders).

Session Variables

$session.user           as CurrentUser,
$session.client         as CurrentClient,
$session.system_date    as SystemDate,
$session.system_language as SystemLanguage,

Joins

define view entity ZI_OrderWithCustomer
  as select from zsalesorder as so
  inner join zcustomer as cust
    on so.customer_id = cust.customer_id
{
  key so.order_id      as OrderId,
      cust.customer_name as CustomerName,
      so.net_amount     as NetAmount
}
Join TypeKeywordBehavior
Innerinner joinOnly matching rows
Left Outerleft outer joinAll from left + matching right
Right Outerright outer joinAll from right + matching left
Crosscross joinCartesian product

Note: Prefer associations over joins when possible — associations are lazily resolved and support path expressions.

Key Annotations

Semantics Annotations (for managed fields in RAP)

@Semantics.user.createdBy: true
created_by as CreatedBy,

@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,

@Semantics.user.localInstanceLastChangedBy: true
last_changed_by as LastChangedBy,

@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,

@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt,

Amount & Currency / Quantity & Unit

@Semantics.amount.currencyCode: 'CurrencyCode'
net_amount as NetAmount,

currency_code as CurrencyCode,

@Semantics.quantity.unitOfMeasure: 'QuantityUnit'
quantity as Quantity,

quantity_unit as QuantityUnit,

UI Annotations (in CDS or Metadata Extensions)

@UI.headerInfo: {
  typeName: 'Sales Order',
  typeNamePlural: 'Sales Orders',
  title: { type: #STANDARD, value: 'OrderId' }
}

@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
order_id as OrderId,

Metadata Extensions (recommended for UI annotations)

@Metadata.layer: #CUSTOMER
annotate view ZC_SalesOrder with
{
  @UI.facet: [{
    id: 'GeneralInfo',
    type: #IDENTIFICATION_REFERENCE,
    label: 'General Information',
    position: 10
  }]

  @UI.lineItem: [{ position: 10, importance: #HIGH }]
  @UI.identification: [{ position: 10 }]
  OrderId;

  @UI.lineItem: [{ position: 20 }]
  @UI.identification: [{ position: 20 }]
  @UI.selectionField: [{ position: 10 }]
  CustomerId;

  @UI.lineItem: [{ position: 30 }]
  @UI.identification: [{ position: 30 }]
  NetAmount;
}

CDS Access Control

@EndUserText.label: 'Access Control for Sales Order'
@MappingRole: true
define role ZR_SalesOrder
{
  grant select on ZR_SalesOrder
  where ( CustomerId ) = aspect pfcg_auth ( Z_SO_AUTH, CUSTOMER_ID, ACTVT = '03' );
}

Access Control Patterns

PatternDescription
pfcg_authStandard authorization object check
inheritInherit restrictions from associated entity
aspect userRestrict by current user
true / falseUnrestricted / no access
// Inherit from parent entity
define role ZR_SalesOrderItem {
  grant select on ZR_SalesOrderItem
  where inheriting conditions from entity ZR_SalesOrder
    association _Order;
}

// User-based restriction
define role ZR_MyOrders {
  grant select on ZR_SalesOrder
  where CreatedBy = aspect user;
}

CDS Table Entities

define table entity ztab_salesorder {
  key client    : abap.clnt;
  key order_uuid: sysuuid_x16;
      order_id  : abap.numc(10);
      customer  : abap.char(10);
      amount    : abap.dec(15,2);
      currency  : abap.cuky(5);
}

CDS table entities can serve as alternatives to classic DDIC database tables and can be used as persistent table in RAP BDEFs.

Data Model Patterns for RAP

Typical Composition Tree

ZR_Root (define root view entity)
├── composition [0..*] of ZR_Child1 as _Child1
└── composition [0..*] of ZR_Child2 as _Child2
    └── composition [0..*] of ZR_GrandChild as _GrandChild

ZR_Child1 (association to parent ZR_Root as _Root)
ZR_Child2 (association to parent ZR_Root as _Root)
  └── composition [0..*] of ZR_GrandChild as _GrandChild
ZR_GrandChild (association to parent ZR_Child2 as _Parent)

Admin Field Pattern (Managed RAP BO)

Every entity in a managed RAP BO should include admin fields:

FieldTypeAnnotationPurpose
CreatedBysyuname@Semantics.user.createdBy: trueWho created
CreatedAtutclong@Semantics.systemDateTime.createdAt: trueWhen created
LastChangedBysyuname@Semantics.user.localInstanceLastChangedBy: trueWho last changed
LocalLastChangedAtutclong@Semantics.systemDateTime.localInstanceLastChangedAt: trueETag for optimistic concurrency
LastChangedAtutclong@Semantics.systemDateTime.lastChangedAt: trueTotal ETag for draft

Output Format

  • Provide complete CDS source code when creating new views
  • Include all relevant annotations
  • Follow naming conventions (ZR_* for interface, ZC_* for consumption, ZI_* for reuse)
  • Always expose associations used in consumption
  • Include access control definitions when security is relevant

References

Capabilities

skillsource-likweitanskill-cds-view-entitiestopic-abaptopic-agent-skillstopic-sap

Install

Installnpx skills add likweitan/abap-skills
Transportskills-sh
Protocolskill

Quality

0.46/ 1.00

deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 12 github stars · SKILL.md body (14,009 chars)

Provenance

Indexed fromgithub
Enriched2026-04-24 01:03:16Z · deterministic:skill-github:v1 · v1
First seen2026-04-23
Last seen2026-04-24

Agent access