Skip to content
Merged

@assert #2216

Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
58b81af
content
StefanHenke Nov 19, 2025
6ca8d04
Update guides/providing-services.md
StefanHenke Nov 20, 2025
f5f5f84
incorporate feedback
StefanHenke Nov 20, 2025
1953da0
fix cds syntax
StefanHenke Nov 20, 2025
c17c192
Update guides/providing-services.md
StefanHenke Nov 21, 2025
7bffed3
real life samples
StefanHenke Nov 21, 2025
e77e067
fix cds syntac
StefanHenke Nov 21, 2025
baa450c
Update guides/providing-services.md
StefanHenke Nov 24, 2025
7c18cb5
Update guides/providing-services.md
StefanHenke Nov 24, 2025
c368a2b
Update guides/providing-services.md
StefanHenke Nov 24, 2025
1069742
Update guides/providing-services.md
rjayasinghe Nov 27, 2025
a929b44
Update guides/providing-services.md
rjayasinghe Nov 27, 2025
9be2cc2
Apply suggestion from @agoerler
rjayasinghe Nov 27, 2025
5b9016d
Apply suggestion from @schwma
rjayasinghe Nov 27, 2025
bcb4ab3
Apply suggestion from @patricebender
rjayasinghe Nov 27, 2025
846d465
Apply suggestion from @Akatuoro
rjayasinghe Nov 27, 2025
e536412
rephrase first section of @assert docu
rjayasinghe Nov 25, 2025
53cd987
move section about i18n and message keys down to error function
rjayasinghe Nov 27, 2025
caa6f57
Merge remote-tracking branch 'origin/main' into assert-docs
rjayasinghe Nov 28, 2025
45b6781
use smaller code box instead of disfunctional code focus
rjayasinghe Nov 28, 2025
884a35c
remove section about error function
rjayasinghe Nov 28, 2025
fafff8f
apply review comments
rjayasinghe Nov 28, 2025
90a9715
Update guides/providing-services.md
StefanHenke Dec 1, 2025
9cb4a42
Update guides/providing-services.md
StefanHenke Dec 1, 2025
f3148de
incorporate feedback
StefanHenke Dec 1, 2025
60f8d3c
Merge remote-tracking branch 'origin' into assert-docs
StefanHenke Dec 1, 2025
d055d98
:Merge remote-tracking branch 'origin/assert-docs' into assert-docs
StefanHenke Dec 1, 2025
4d4891d
revert ternary comment
StefanHenke Dec 1, 2025
4b0360d
fix code snippets
StefanHenke Dec 2, 2025
b605960
remove parenthesis
StefanHenke Dec 2, 2025
9fef206
Merge remote-tracking branch 'origin/main' into assert-docs
agoerler Dec 11, 2025
dfcdbd7
add disclaimers
agoerler Dec 11, 2025
9824347
Apply suggestions from code review
agoerler Dec 11, 2025
00cc8cc
Apply suggestions from code review
StefanHenke Dec 12, 2025
3cdf60d
fix linting issues
StefanHenke Dec 12, 2025
2e55c00
fix ternary expressions
StefanHenke Dec 12, 2025
9eb51b2
incorporate feedback
StefanHenke Dec 15, 2025
22dfb34
Merge branch 'main' into assert-docs
StefanHenke Dec 15, 2025
9526c32
incorporate latest feedback
StefanHenke Dec 15, 2025
cd4accc
incorporate latest feedback
StefanHenke Dec 15, 2025
278095c
incorporate latest feedback
StefanHenke Dec 15, 2025
aa58ba8
Apply suggestions from code review
renejeglinsky Dec 15, 2025
9e8459d
Merge branch 'main' into assert-docs
danjoa Dec 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions guides/providing-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,125 @@ Cross-service checks are not supported. It is expected that the associated entit
The `@assert.target` check constraint relies on database locks to ensure accurate results in concurrent scenarios. However, locking is a database-specific feature, and some databases don't permit to lock certain kinds of objects. On SAP HANA, for example, views with joins or unions can't be locked. Do not use `@assert.target` on such artifacts/entities.
:::

### `@assert` <Beta/>

Annotate an _element_ with `@assert` to define the CXL expressions that are validated _after_ the data has been written to the database but _before_ it is committed. If the validation fails, the expression will return a `String` that indicates an error to the runtime. If the validation passes the expression return `null`

```cds
entity OrderItems : cuid {

@assert: (case
when quantity <= 0 then 'Quantity must be greater than zero'
end)
quantity : Integer;
}
```

Alternatively, the same condition can be simplified by using the [ternary conditional operator](../releases/archive/2023/march23#ternary-conditional-operator):

```cds
entity OrderItems : cuid {

@assert: (quantity <= 0 ? 'Quantity must be greater than zero' : null)
quantity : Integer;
}
```

#### Error Messages and Message Targets

If a validation fails, the transaction is rolled back with an exception. If you use [Fiori draft state messages](../advanced/fiori#validating-drafts) the error is persisted. The error targets the annotated element, which is then highlighted on the Fiori UI.

::: info Error Messages
The error message returned by the CXL expression inside the annotation can be either a static message or a message key to support i18n. If a message key is used, the message is looked up in the message bundle of the service.
[Learn more about localized messages](./i18n){.learn-more}
:::


#### Complex Asserts

::: warning Use complex asserts on service layer
Like other annotations, `@assert` is propagated to projections. If you annotate an element with `@assert` and the condition uses other elements - from the same or an associated entity - you must ensure that these elements are available in all projections to which the annotated element is propagated. Otherwise the CDS model won't compile.

It is therefore recommended to use complex asserts on the highest projection, that is on the service layer.
:::

For the examples given in this section, consider the following CDS _domain_ and _service_ model:

```cds
context db {
entity Books : cuid {
title : String;
stock : Integer;
deliveryDate : Date;
orderDate : Date;
}

entity Orders : cuid {
items : Composition of many OrderItems on items.order = $self;
}

entity OrderItems : cuid {
order : Association to Orders;
book : Association to Books;
quantity : Integer;
}
}

service OrderService {
entity Orders as projection on db.Orders;
entity OrderItems as projection on db.OrderItems;
}
```

An `@assert` annotation may use other elements from the same entity. This annotation checks that the delivery date of an order is after the order date:

```cds
annotate OrderService.Orders with {
deliveryDate @assert: (deliveryDate < orderDate ? 'DELIVERY_BEFORE_ORDER' : null); // [!code highlight]
}
```
In an `@assert` condition you can also refer to elements of associated entities. The following example ensures that the `quantity` of the ordered book is validated against the actual `stock`. If the stock level is insufficient, a static error message is returned:

```cds
annotate OrderService.OrderItems with {
quantity @assert: (case // [!code highlight]
when book.stock <= quantity then 'Stock exceeded' // [!code highlight]
end); // [!code highlight]
}
```

You can also perform validations based on entities associated via a to-many association. Use an [exists predicate](../cds/cql#exists-predicate) in this case:

```cds
annotate OrderService.Orders with {
items @assert: ( exists items[book.isNotReleased = true] // [!code highlight]
? 'Some ordered book is not yet released' : null) // [!code highlight]
}
```

Refer to [Expressions as Annotation Values](../cds/cdl.md#expressions-as-annotation-values) for detailed rules on expression syntax.

#### Multiple Conditions

Use multiple `when` clauses to check multiple conditions with a single `@assert` annotation. Each condition returns its own error message to precisely describe the error:

```cds
annotate OrderService.OrderItems with {
quantity @assert: (case
when book.stock = 0 then 'Stock is zero'
when book.stock <= quantity then 'Stock exceeded'
end)
}
```

#### Background

Expressions are evaluated *after* the request has been applied to the underlying datastore. Affected are the entities of the request's payload. The runtime executes check-statements with the provided expressions and the primary key values for the given entities.

::: warning Limitations
- All primary key fields need to be contained in the CQN statement for validations to be enforced (including deep insert and deep update).
- Only elements with simple types (like, `String`, `Integer`, `Boolean`) can be annotated with `@assert`. Elements typed with structured or arrayed types are not supported.
:::

### Custom Error Messages

Expand Down