mcpField
C
cds-view-entities

cds-view-entities

github.com/likweitanデータ・データベース7297 回インストール2 週間前に更新
リポジトリ

cds-view-entities について

ABAP CloudでABAP CDSビューエンティティを使い、意味のあるデータモデルを設計するためのガイドです。関連、アノテーション、アクセス制御、RAP向けパターンに加え、SAPデータアクセスのクリーンコア指針も扱います。

主な機能

  1. 01CDSビューエンティティの設計
  2. 02関連とコンポジション
  3. 03式と組み込み関数
  4. 04UI、セマンティクス、分析アノテーション
  5. 05CDSアクセス制御のパターン
  6. 06RAPデータモデルの構成

活用シーン

  1. 01単独利用またはRAP向けのCDSモデル作成
  2. 02親子エンティティ関係のモデリング
  3. 03UIメタデータやセマンティクスアノテーションの追加
  4. 04データアクセス制限の定義

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/likweitan/abap-skills --skill cds-view-entities

インストール後、Claude Code で/cds-view-entitiesを入力して読み込まれたか確認します。

同梱ファイルreferences/annotation-reference.md

詳細

CDS ビューエンティティ

ABAP Cloud で ABAP CDS(Core Data Services)ビューエンティティを使用して、セマンティックデータモデルを構築するためのガイドです。

クリーンコアのコンテキスト:リリース済みの SAP CDS ビュー(I_*)から選択するのは レベル A です。SAP データベーステーブルへの直接の読み取りアクセスは レベル C(ATC 優先度 2)、直接の書き込みアクセスは レベル D(ATC 優先度 1)です。リリース済み CDS ビューが存在しない場合は、未リリースの SAP ビューまたはテーブルの上にラッパー CDS ビューを構築し、ABAP Cloud 向けにリリースします。ラップするオブジェクトがクラシック API の場合、ラッパーはレベル B、それ以外の場合はレベル C です。SAP CDS ビューを変更するのではなく、CDS 拡張とCDS メタデータ拡張を使用してください。レベルの詳細については、abap-cloud スキルを参照してください。

ワークフロー

  1. ユーザーの目的を特定します:

    • 新しいデータモデルを作成する(単独、または RAP 用)
    • エンティティ間の関係を定義する(アソシエーション、コンポジション)
    • UI、セマンティクス、または分析向けのアノテーションを追加する
    • アクセス制御を実装する
    • CDS で式、関数、またはパラメーターを使用する
  2. コンテキストを特定します:

    • 単独の CDS ビューか、RAP BO データモデルか
    • ルートエンティティか、子エンティティか、プロジェクションビューか
    • トランザクション処理(RAP)か、分析用か、読み取り専用の利用か
  3. ベストプラクティスを適用します:

    • CDS ビューエンティティ(v2 構文の define view entity)を使用します。従来の CDS ビュー(define view)は使用しません。
    • 命名規則に従います(例:インターフェース/BO ビューには ZR_*、利用/プロジェクションビューには ZC_*、再利用ビューには ZI_*)。
    • メタデータの利用者(UI、OData、分析)向けに適切なアノテーションを追加します。

CDS ビューエンティティの構文

基本ビューエンティティ
@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
}
ルートビューエンティティ(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
}
子ビューエンティティ
@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
}
プロジェクションビュー(利用レイヤー)
@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
}

アソシエーションとコンポジション

アソシエーションの種類
種類構文使用例
通常のアソシエーションassociation [0..1] to ZI_Customer as _Customer on ...独立したエンティティ(例:マスターデータの検索)
コンポジションcomposition [0..*] of ZR_Child as _Childライフサイクルに依存する親子関係(RAP BO ツリー)
親へのアソシエーションassociation to parent ZR_Parent as _Parent on ...コンポジション内で子から親への参照
アソシエーションの構文
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
}
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).

式と組み込み関数

キャスト式
cast( amount as abap.dec(15,2) ) as ConvertedAmount,
cast( status as abap.char(10) )  as StatusText,
CASE 式
// 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,
算術式
quantity * unit_price as TotalPrice,
net_amount + tax_amount as GrossAmount,
文字列関数
concat( first_name, concat( ' ', last_name ) ) as FullName,
substring( postal_code, 1, 2 )                 as Region,
length( description )                          as DescLength,
upper( country_code )                          as CountryUpper,
日付と時刻の関数
dats_days_between( start_date, end_date ) as DurationDays,
dats_add_days( order_date, 30 )           as DueDate,
tstmp_current_utctimestamp()              as CurrentTimestamp,
集約式
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
入力パラメーター
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

ABAP SQL での使用:

SELECT FROM zi_salesorderbydate( p_date = @lv_date )
  FIELDS OrderId, OrderDate, NetAmount
  INTO TABLE @DATA(lt_orders).
セッション変数
$session.user           as CurrentUser,
$session.client         as CurrentClient,
$session.system_date    as SystemDate,
$session.system_language as SystemLanguage,

結合

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
}
結合の種類キーワード動作
内部結合inner join一致する行のみ
左外部結合left outer join左側のすべての行と、一致する右側の行
右外部結合right outer join右側のすべての行と、一致する左側の行
クロス結合cross joinデカルト積

注:可能な場合は、結合よりもアソシエーションを優先してください。アソシエーションは遅延解決され、パス式をサポートします。

主なアノテーション

セマンティクスアノテーション(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,
金額と通貨/数量と単位
@Semantics.amount.currencyCode: 'CurrencyCode'
net_amount as NetAmount,

currency_code as CurrencyCode,

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

quantity_unit as QuantityUnit,
UI アノテーション(CDS またはメタデータ拡張内)
@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,
メタデータ拡張(UI アノテーションに推奨)
@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 アクセス制御

@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' );
}
アクセス制御パターン
パターン説明
pfcg_auth標準の権限オブジェクトチェック
inherit関連エンティティの制限を継承する
aspect user現在のユーザーで制限する
true / false制限なし/アクセス不可
// 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 テーブルエンティティ

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 テーブルエンティティは、従来の DDIC データベーステーブルの代替として利用でき、RAP BDEF では persistent table として使用できます。

RAP のデータモデルパターン

典型的なコンポジションツリー
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)
管理フィールドパターン(マネージド RAP BO)

マネージド RAP BO の各エンティティには、管理フィールドを含める必要があります。

フィールド型アノテーション用途
CreatedBysyuname@Semantics.user.createdBy: true作成者
CreatedAtutclong@Semantics.systemDateTime.createdAt: true作成日時
LastChangedBysyuname@Semantics.user.localInstanceLastChangedBy: true最終変更者
LocalLastChangedAtutclong@Semantics.systemDateTime.localInstanceLastChangedAt: true楽観的同時実行制御用 ETag
LastChangedAtutclong@Semantics.systemDateTime.lastChangedAt: trueドラフト用の合計 ETag

出力形式

  • 新しいビューを作成する場合は、CDS ソースコード全体を提示してください
  • 関連するアノテーションをすべて含めてください
  • 命名規則に従ってください(インターフェースは ZR_*、コンシュームは ZC_*、再利用は ZI_*)
  • コンシュームで使用するアソシエーションは常に公開してください
  • セキュリティに関係する場合は、アクセス制御定義を含めてください

参考資料

CDS の Clean Core レベルに関する注意事項

シナリオレベル注意事項
リリース済みの SAP CDS ビュー(I_*)に対する SELECTA目標状態
独自のテーブルを基にしたカスタム CDS ビューA同じソフトウェアコンポーネント内で許可されます
クラシック(指定済み)の SAP CDS ビューに対する SELECTBクラシック ABAP 開発では許容されます
リリースされていない SAP CDS ビューを基にしたラッパー CDS ビューB/Cラップ対象のビューがクラシック API の場合は B、それ以外は C
SAP データベーステーブルへの直接的な読み取りアクセスCATC 優先度 2 — リリース済みの CDS ビューまたはクラシック API を使用します
SAP データベーステーブルへの直接的な書き込みアクセスDATC 優先度 1 — リリース済みまたはクラシック API を使用します
SAP CDS ビューに対する CDS extend/メタデータ拡張A/B変更よりも推奨されます
リリース済み拡張インクルードを使用したカスタムフィールドA推奨される手法
リリースされていない拡張インクルードを使用したカスタムフィールドBリリース済みのインクルードを監視します
クラシックな APPEND を使用したカスタムフィールドC拡張インクルードが利用可能になったら移行を検討します
ラッパー CDS ビューに関するガイダンス
  • 適切な SAP CDS ビューが存在するもののリリースされていない場合は、その上にカスタム CDS ビューを作成し、ABAP Cloud 開発向けにリリースします
  • SAP ビューが参照する CDS ビュー(関連付けのターゲット、値ヘルプビュー)にも、それぞれラッパーが必要になる場合があります
  • 適切な SAP CDS ビューがまったく存在しない場合は、データベーステーブル上にカスタム CDS ビューを直接作成します
  • SAP が同等の CDS ビューをリリースしたら、ラッパーを廃止します

CDS ビューは、Cloudification Repository でオブジェクトタイプ STOB として分類されます。

関連スキル

  • abap-sql-amdp:高度な ABAP SQL クエリおよび AMDP プロシージャに使用します
  • rap:CDS データモデルに基づく RAP ビジネスオブジェクトの構築に使用します
  • authorization-iam:CDS アクセス制御(DCL)の実装に使用します
  • odata:CDS ビューを OData サービスとして公開するために使用します
  • abap-cloud:Clean Core レベルの分類およびラッパー CDS ビューのパターンに使用します
  • abap-cloud-migration:テーブルへの直接アクセスをリリース済み CDS ビューに置き換えるために使用します

コメント