# Update with ARX.SDK on Amazon DynamoDB

## What an update does

| Rule | On DynamoDB |
|---|---|
| What is written | Only the attributes present (`SET`); an attribute set to null is removed (`REMOVE`): DynamoDB keeps no empty attributes |
| Which item | By its full key: the id (with the key's other attributes, such as an order's customer), or `ArxMatch.Columns`/`ArxMatch.Key` naming exactly the key's attributes |
| Other columns | When they give a partition key, of the table or an index: one query finds the items (at most 100), then each is updated by its key, all or nothing, conditioned on still matching (an index can be behind the table). The match columns are never written; RequireSingleRow refuses several (ARX2003) |
| No partition | ARX8001: a write never scans |
| Nothing matched | ARX2002 RecordNotFound: the update is conditional on the item existing, so it never creates one |
| Index keys | When an attribute an index is keyed by changes, give the index key's other attributes too: ARX rewrites the index keys |
| The table's keys | `PK`, `SK`, the index key attributes and `entity_type` are ARX's to write, and can't be matched on (ARX1001) |
| A new key | An entity whose `RecordId` and id attribute differ is ARX1001, unless `new ArxDynamoWriteOptions { AllowKeyChange = true }`: the item is read, changed, put under its new key (ARX3001 if taken) and the old one deleted, in one transaction |
| Concurrency | A version attribute declared in the schema catalog (`.Version("product", "row_version")`): a create writes 1; an update whose entity carries the version it read is written only if the item still has it (ARX2004 RecordChanged otherwise, nothing written) and adds one. Without the version the update isn't checked: the last writer wins, and the version still goes up |
| Names | Placeholders only (`#n0`); expression or SQL syntax in a name is ARX1017 |
| Rows by a condition | Update finds rows by equal values: the id, a declared key, or columns you give values for (`ArxMatch.Columns`). To change every row that meets a condition (`amount > 100`), pass the values and an `ArxFilterExpression` to `UpdateMultipleAsync(values, filter)` (the filter must give a partition key; at most 100 items): one call, all or nothing, from 0.1.0-preview.5 (UpdateMultiple, Basics). Before that version: read the rows with `RetrieveMultipleAsync` and pass them to `UpdateMultipleAsync`. |

## The samples

Every Update sample, in reading order. Each scenario shows the code (verified against DynamoDB Local) and the PartiQL statement that checks what it did. `service` is the application's `ArxDynamoDbService`; values marked "In scope" come from earlier in the sample. What the samples' code refers to beyond the packages (SampleCatalog.cs, `dbContext`) is in the sample application file, arx-dynamodb-sample-application.md.

### Update one record

Basics 1 of Update.

The smallest update, in three scenarios: by the id Create returned, clearing a value, and an item that isn't there.

Good to know:

Only the attributes you set are written (`SET`); an attribute set to null is removed from the item (`REMOVE`: DynamoDB keeps no empty attributes). The update is conditional on the item existing, so nothing matched is ARX2002 and never creates an item.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var product = new ArxEntity("product");
product["sku"] = "SKU-D261";
product["name"] = "Rain jacket";
product["price"] = 89.00m;
product["colour"] = "Navy";
var id = await service.CreateAsync(product);
```

#### 1. By the id Create returned

Give the entity the id CreateAsync returned, and only the attributes to change.

In scope: `service` (ArxDynamoDbService), `id` (ArxRecordId).

```csharp
var change = new ArxEntity("product") { RecordId = id };
change["price"] = 79.00m;

int changed = await service.UpdateAsync(change);

Console.WriteLine($"{changed} item changed");
```

Check it in the database:

```sql
SELECT "name", "price" FROM "product" WHERE "sku" = 'SKU-D261'
```

Expect: 1 item, Rain jacket, price 79.

#### 2. Clear a value

Null removes the attribute.

In scope: `service` (ArxDynamoDbService), `id` (ArxRecordId).

```csharp
var change = new ArxEntity("product") { RecordId = id };
change["colour"] = null;

await service.UpdateAsync(change);

Console.WriteLine("colour removed");
```

Check it in the database:

```sql
SELECT * FROM "product" WHERE "sku" = 'SKU-D261'
```

Expect: 1 item, with no colour attribute.

#### 3. An item that isn't there

A SKU no item has: ARX2002, and no item is created.

In scope: `service` (ArxDynamoDbService).

```csharp
var change = new ArxEntity("product") { RecordId = ArxRecordId.Of("sku", "SKU-D269") };
change["price"] = 1.00m;

try
{
    await service.UpdateAsync(change);
}
catch (ArxException exception) when (exception.Code == ArxErrorCode.RecordNotFound)
{
    Console.WriteLine(exception.Message);
}
```

Check it in the database:

```sql
SELECT "sku" FROM "product" WHERE "sku" = 'SKU-D269'
```

Expect: no items.

### How an update finds its item

Basics 2 of Update.

How an update finds its item in DynamoDB, in four scenarios: an order by its id and its customer, by its key's attributes, every order a query of the customer's partition finds, and a match no partition answers.

Good to know:

DynamoDB writes an item by its full key. An order's key is its customer and its number, so its id alone isn't enough: give the customer too. A match by other columns works when they give a partition key, of the table or an index: ARX queries it, then updates each item found by its key, all or nothing (at most 100), each conditioned on still matching. Without a partition it is ARX8001: a write never scans. When an attribute an index is keyed by changes (the status), give the index key's other attributes too (the date): ARX rewrites the index keys from them.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var customer = new ArxEntity("customer");
customer["customer_id"] = "C-D211";
customer["name"] = "Tailspin Toys";
await service.CreateAsync(customer);
var orders = new[] { "SO-D211", "SO-D212" }.Select(number =>
{
    var order = new ArxEntity("sales_order");
    order["customer_id"] = "C-D211";
    order["order_number"] = number;
    order["status"] = "OPEN";
    order["ordered_on"] = "2026-11-02";
    return order;
}).ToList();
await service.CreateMultipleAsync(orders);
```

#### 1. By the id and the customer

The id Create returned plus the customer: ship SO-D211 (with its date, so ARX rewrites the GSI1 keys).

In scope: `service` (ArxDynamoDbService).

```csharp
var change = new ArxEntity("sales_order") { RecordId = ArxRecordId.Of("order_number", "SO-D211") };
change["customer_id"] = "C-D211";
change["status"] = "SHIPPED";
change["ordered_on"] = "2026-11-02";

await service.UpdateAsync(change);

Console.WriteLine("SO-D211 shipped");
```

Check it in the database:

```sql
SELECT "status", "GSI1PK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D211' AND "SK" = 'ORDER#SO-D211'
```

Expect: 1 item, status "SHIPPED", GSI1PK "STATUS#SHIPPED".

#### 2. By the key's attributes

ArxMatch.Columns naming exactly the key's attributes: the same thing, said explicitly.

In scope: `service` (ArxDynamoDbService).

```csharp
var change = new ArxEntity("sales_order");
change["customer_id"] = "C-D211";
change["order_number"] = "SO-D212";
change["status"] = "CANCELLED";
change["ordered_on"] = "2026-11-02";

await service.UpdateAsync(change, new ArxUpdateOptions { Match = ArxMatch.Columns("customer_id", "order_number") });

Console.WriteLine("SO-D212 cancelled");
```

Check it in the database:

```sql
SELECT "status" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D211' AND "SK" = 'ORDER#SO-D212'
```

Expect: 1 item, status "CANCELLED".

#### 3. Through a query

Every order of the customer, through a query of its partition: each found order updated by its key.

In scope: `service` (ArxDynamoDbService).

```csharp
var change = new ArxEntity("sales_order");
change["customer_id"] = "C-D211";
change["priority"] = "high";

int changed = await service.UpdateAsync(change, new ArxUpdateOptions { Match = ArxMatch.Columns("customer_id") });

Console.WriteLine($"{changed} orders marked high priority");
```

Check it in the database:

```sql
SELECT "order_number", "priority" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D211' AND begins_with("SK", 'ORDER#')
```

Expect: 2 items, SO-D211 and SO-D212, both priority "high".

#### 4. No partition

Every order of a date: no partition key in the match, so ARX8001 rather than a scan.

In scope: `service` (ArxDynamoDbService).

```csharp
var change = new ArxEntity("sales_order");
change["ordered_on"] = "2026-11-02";
change["priority"] = "low";

try
{
    await service.UpdateAsync(change, new ArxUpdateOptions { Match = ArxMatch.Columns("ordered_on") });
}
catch (ArxNotSupportedException exception)
{
    Console.WriteLine(exception.Message);
}
```

Check it in the database:

```sql
SELECT "order_number", "priority" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D211' AND begins_with("SK", 'ORDER#')
```

Expect: 2 items, both still priority "high".

### Catch an injection attempt

Real case 1 of Update.

A "profile" endpoint whose posted fields become the attributes to change, attacked two ways: an update expression in a field name, and a field that tries to rewrite the item's key; then the same form used honestly.

Good to know:

Names reach DynamoDB only as placeholders (`#n0`), so a name can't add clauses to the update expression: one with expression syntax is ARX1017 before anything is sent. The table's own key attributes (`PK`, `SK`) are ARX's to write, never the caller's.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var customer = new ArxEntity("customer");
customer["customer_id"] = "C-D221";
customer["name"] = "Coho Winery";
customer["tier"] = "standard";
await service.CreateAsync(customer);
```

#### 1. An expression in a field name

"name = :v0, tier" tries to set the tier too: ARX1017.

In scope: `service` (ArxDynamoDbService).

```csharp
try
{
    await UpdateProfileAsync(service, new() { ["name = :v0, tier"] = "gold" });
}
catch (ArxValidationException exception) when (exception.Code == ArxErrorCode.SuspectedInjection)
{
    Console.WriteLine(exception.Message);
}
```

Defined in the sample, used above:

```csharp
private static Task<int> UpdateProfileAsync(ArxDynamoDbService service, Dictionary<string, object> posted)
{
    var change = new ArxEntity("customer") { RecordId = ArxRecordId.Of("customer_id", "C-D221") };

    foreach (var field in posted)
    {
        change[field.Key] = field.Value;
    }

    return service.UpdateAsync(change);
}
```

Check it in the database:

```sql
SELECT "tier" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D221' AND "SK" = 'PROFILE'
```

Expect: 1 item, tier "standard".

#### 2. Rewrite the key

A posted "PK" field: the table's key belongs to ARX, so it's refused.

In scope: `service` (ArxDynamoDbService).

```csharp
try
{
    await UpdateProfileAsync(service, new() { ["PK"] = "CUSTOMER#someone-else" });
}
catch (ArxException exception)
{
    Console.WriteLine(exception.Message);
}
```

Check it in the database:

```sql
SELECT "PK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D221'
```

Expect: 1 item, still under CUSTOMER#C-D221.

#### 3. The honest request

The same endpoint, used as meant.

In scope: `service` (ArxDynamoDbService).

```csharp
await UpdateProfileAsync(service, new() { ["name"] = "Coho Winery & Vineyard" });

Console.WriteLine("name changed");
```

Check it in the database:

```sql
SELECT "name" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D221' AND "SK" = 'PROFILE'
```

Expect: 1 item, name "Coho Winery & Vineyard".

### Detect a change made since the read

Real case 2 of Update.

Two people edit the same product: optimistic concurrency with a version attribute, in four scenarios: a create starts the version at 1, the first save wins, the second is told the item changed, and an update without the version.

Good to know:

Declare the version attribute in the schema catalog: `.Version("product", "row_version")`. A create writes 1 when the entity gives none. An update or a delete whose entity carries the version it read is written only if the item still has it, and an update adds one; otherwise it is ARX2004 RecordChanged and nothing is written (one round trip: the failed write returns the item, so a missing item is still ARX2002). An update without the version isn't checked: the last writer wins, though the version still goes up. So read the version with the item, and send it back with the change. A move to a new key (AllowKeyChange) checks the version too.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var schema = ArxSchemaCatalog.Create()
    .Table("product", ArxIdColumn.Supplied<string>("sku"))
    .Version("product", "row_version")
    .Build();
var service = new ArxDynamoDbService(dbContext.Client, dbContext.Model, schema);
```

#### 1. A create starts the version at 1

Create a product: ARX writes its version, 1.

In scope: `service` (ArxDynamoDbService).

```csharp
var product = new ArxEntity("product");
product["sku"] = "SKU-D271";
product["name"] = "Trail running shoe";
product["price"] = 129.90m;
await service.CreateAsync(product);

var read = await service.RetrieveAsync("product", "SKU-D271") ?? throw new InvalidOperationException("The product record isn't there.");
Console.WriteLine($"{read["name"]}, version {read["row_version"]}");
```

Check it in the database:

```sql
SELECT "sku", "price", "row_version" FROM "product" WHERE "sku" = 'SKU-D271'
```

Expect: 1 item, price 129.90, row_version 1.

#### 2. The first save wins

Ana and Ben both read version 1; Ana saves first, with the version she read: written, now version 2.

In scope: `service` (ArxDynamoDbService).

```csharp
var ana = await service.RetrieveAsync("product", "SKU-D271") ?? throw new InvalidOperationException("The product record isn't there.");

var change = new ArxEntity("product");
change["sku"] = "SKU-D271";
change["price"] = 119.90m;
change["row_version"] = ana["row_version"];
await service.UpdateAsync(change);

var read = await service.RetrieveAsync("product", "SKU-D271") ?? throw new InvalidOperationException("The product record isn't there.");
Console.WriteLine($"Ana's price {read["price"]}, version {read["row_version"]}");
```

Check it in the database:

```sql
SELECT "price", "row_version" FROM "product" WHERE "sku" = 'SKU-D271'
```

Expect: price 119.90, row_version 2.

#### 3. The second save is told the item changed

Ben saves with the version 1 he read: ARX2004, nothing written; he reads again and saves with version 2.

In scope: `service` (ArxDynamoDbService).

```csharp
var stale = new ArxEntity("product");
stale["sku"] = "SKU-D271";
stale["name"] = "Trail running shoe, wide";
stale["row_version"] = 1;

try
{
    await service.UpdateAsync(stale);
}
catch (ArxException exception) when (exception.Code == ArxErrorCode.RecordChanged)
{
    Console.WriteLine(exception.Message);
}

// Ben reads what is there now, and applies his change to it.
var now = await service.RetrieveAsync("product", "SKU-D271") ?? throw new InvalidOperationException("The product record isn't there.");
var retry = new ArxEntity("product");
retry["sku"] = "SKU-D271";
retry["name"] = "Trail running shoe, wide";
retry["row_version"] = now["row_version"];
await service.UpdateAsync(retry);

var read = await service.RetrieveAsync("product", "SKU-D271") ?? throw new InvalidOperationException("The product record isn't there.");
Console.WriteLine($"{read["name"]}, price {read["price"]}, version {read["row_version"]}");
```

Check it in the database:

```sql
SELECT "name", "price", "row_version" FROM "product" WHERE "sku" = 'SKU-D271'
```

Expect: Trail running shoe, wide; price 119.90 (Ana's, kept); row_version 3.

#### 4. An update without the version: the last writer wins

An update without the version isn't checked: it is written whatever the item's version, which still goes up.

In scope: `service` (ArxDynamoDbService).

```csharp
var blind = new ArxEntity("product");
blind["sku"] = "SKU-D271";
blind["price"] = 99.90m;
await service.UpdateAsync(blind);

var read = await service.RetrieveAsync("product", "SKU-D271") ?? throw new InvalidOperationException("The product record isn't there.");
Console.WriteLine($"price {read["price"]}, version {read["row_version"]}");
```

Check it in the database:

```sql
SELECT "price", "row_version" FROM "product" WHERE "sku" = 'SKU-D271'
```

Expect: price 99.90, row_version 4.

### Update in a batch scope

Advanced case 1 of Update.

Creates and updates in one batch scope, in two scenarios: committed when the body returns, and nothing written when the body throws.

Good to know:

A batch scope collects its writes and sends them as one `TransactWriteItems` when the body returns: all or nothing, up to 100 writes, and one item may be written once per scope. DynamoDB has no savepoints, so a scope opened with the default options has none (asking for them, with `new ArxBatchOptions { Savepoints = true }`, is refused). A read inside the scope doesn't see its own pending writes.

Usings:

```csharp
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var customer = new ArxEntity("customer");
customer["customer_id"] = "C-D231";
customer["name"] = "Fabrikam Residences";
customer["open_orders"] = 0;
await service.CreateAsync(customer);
```

#### 1. Committed when the body returns

A new order and the customer's open-order count: both or neither.

In scope: `service` (ArxDynamoDbService).

```csharp
await service.RunBatchAsync(async scope =>
{
    var order = new ArxEntity("sales_order");
    order["customer_id"] = "C-D231";
    order["order_number"] = "SO-D231";
    order["status"] = "OPEN";
    order["ordered_on"] = "2026-11-03";
    await scope.CreateAsync(order);

    var count = new ArxEntity("customer") { RecordId = ArxRecordId.Of("customer_id", "C-D231") };
    count["open_orders"] = 1;
    await scope.UpdateAsync(count);
});

Console.WriteLine("order created and the count updated");
```

Check it in the database:

```sql
SELECT "SK", "open_orders" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D231'
```

Expect: 2 items: ORDER#SO-D231, and PROFILE with open_orders 1.

#### 2. Nothing written when the body throws

Your own code fails after the writes: none of them is sent.

In scope: `service` (ArxDynamoDbService).

```csharp
try
{
    await service.RunBatchAsync(async scope =>
    {
        var order = new ArxEntity("sales_order");
        order["customer_id"] = "C-D231";
        order["order_number"] = "SO-D232";
        order["status"] = "OPEN";
        order["ordered_on"] = "2026-11-04";
        await scope.CreateAsync(order);

        throw new InvalidOperationException("the stock check failed");
    });
}
catch (InvalidOperationException exception)
{
    Console.WriteLine($"caught: {exception.Message}");
}
```

Check it in the database:

```sql
SELECT "SK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D231' AND "SK" = 'ORDER#SO-D232'
```

Expect: no items.

### Set up the service from DynamoDB's tables

Advanced case 2 of Update.

The service set up from DynamoDB's description of the lead table, in two scenarios: preload at startup, then update by the preloaded key with Strict on.

Good to know:

The preload makes the table's key (`email`) a business key, so `ArxMatch.Key("email")` finds the item; with `Strict`, an attribute the configuration doesn't declare is ARX1018 before DynamoDB.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.DynamoDb.Model;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Models;
using ARX.SDK.Services;
using Amazon.DynamoDBv2;
```

Set up by the sample before its scenarios:

```csharp
var lead = new ArxEntity("lead");
lead["email"] = "lead-d251@example.com";
lead["full_name"] = "Nuno Teixeira";
lead["score"] = 40;
await service.CreateAsync(lead);
```

#### 1. Preload at startup

Preload the lead table once, at startup, and make the service Strict.

In scope: `client` (IAmazonDynamoDB), `model` (ArxDynamoModel).

```csharp
var catalog = await new ArxPreLoadTable(new ArxPreLoadTableRegister().PreLoadTable("lead")).LoadAsync(client, model, schema => schema
    .Column("lead", new ArxColumnDefinition("full_name", typeof(string), "S", true))
    .Column("lead", new ArxColumnDefinition("score", typeof(int), "N", true)));

catalog.TryGetTable("lead", out var table);
Console.WriteLine($"lead: key {string.Join(", ", table.Keys)}, attributes {string.Join(", ", table.Columns.Keys)}");

return new ArxDynamoDbService(client, model, catalog) { Strict = true };
```

Note: In the AWS CLI: aws dynamodb describe-table --table-name lead --endpoint-url http://localhost:18000 KeySchema email (HASH).

#### 2. Update by the preloaded key

Update by the preloaded key; a misspelt attribute is refused (ARX1018), the right one is written.

In scope: `service` (ArxDynamoDbService).

```csharp
var typo = new ArxEntity("lead");
typo["email"] = "lead-d251@example.com";
typo["scroe"] = 90;

try
{
    await service.UpdateAsync(typo, new ArxUpdateOptions { Match = ArxMatch.Key("email") });
}
catch (ArxValidationException exception) when (exception.Code == ArxErrorCode.NotPreloaded)
{
    Console.WriteLine(exception.Message);
}

var change = new ArxEntity("lead");
change["email"] = "lead-d251@example.com";
change["score"] = 90;
await service.UpdateAsync(change, new ArxUpdateOptions { Match = ArxMatch.Key("email") });
Console.WriteLine("score set to 90");
```

Check it in the database:

```sql
SELECT * FROM "lead" WHERE "email" = 'lead-d251@example.com'
```

Expect: 1 item, score 90 and no scroe attribute.

### Move an item to a new key

Advanced case 3 of Update.

Renumber an order: a new key for an item, in three scenarios: refused unless asked for, the move, and a move onto a number another order has.

Good to know:

DynamoDB can't change an item's key. An entity whose `RecordId` (the item it finds) and id attribute (the new id) differ is ARX1001, unless `new ArxDynamoWriteOptions { AllowKeyChange = true }`: then ARX reads the item, applies the change, puts it under its new key (keys, type and index keys written again) and deletes the old one, in one transaction. A key that is taken is ARX3001, and nothing moves. A change someone else makes between the read and the move is lost, unless the table has a version attribute (see "Detect a change made since the read"): then it is ARX2004.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
foreach (var (number, total) in new[] { ("SO-D261", 120m), ("SO-D269", 45m) })
{
    var order = new ArxEntity("sales_order");
    order["customer_id"] = "C-D261";
    order["order_number"] = number;
    order["status"] = "OPEN";
    order["ordered_on"] = "2026-11-08";
    order["total"] = total;
    await service.CreateAsync(order);
}
```

#### 1. Refused unless asked for

SO-D261 to SO-D262 without the option: ARX1001, nothing changes.

In scope: `service` (ArxDynamoDbService).

```csharp
try
{
    await service.UpdateAsync(Renumber("SO-D261", "SO-D262"));
}
catch (ArxValidationException exception)
{
    Console.WriteLine(exception.Message);
}
```

Defined in the sample, used above:

```csharp
private static ArxEntity Renumber(string from, string to)
{
    var move = new ArxEntity("sales_order") { RecordId = ArxRecordId.Of("order_number", from) };
    move["customer_id"] = "C-D261";
    move["order_number"] = to;
    return move;
}
```

Check it in the database:

```sql
SELECT "SK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D261' AND "SK" = 'ORDER#SO-D261'
```

Expect: 1 item.

#### 2. The move

The move, with a change on the way: SO-D261 becomes SO-D262, its total and index keys kept.

In scope: `service` (ArxDynamoDbService).

```csharp
var move = Renumber("SO-D261", "SO-D262");
move["note"] = "renumbered";

await service.UpdateAsync(move, AllowMove);

Console.WriteLine("SO-D261 is now SO-D262");
```

Defined in the sample, used above:

```csharp
private static readonly ArxDynamoWriteOptions AllowMove = new() { AllowKeyChange = true };

private static ArxEntity Renumber(string from, string to)
{
    var move = new ArxEntity("sales_order") { RecordId = ArxRecordId.Of("order_number", from) };
    move["customer_id"] = "C-D261";
    move["order_number"] = to;
    return move;
}
```

Check it in the database:

```sql
SELECT "SK", "total", "note", "GSI1PK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D261' AND begins_with("SK", 'ORDER#SO-D26')
```

Expect: 2 items: ORDER#SO-D262 (total 120, note "renumbered", GSI1PK "STATUS#OPEN") and ORDER#SO-D269.

#### 3. Onto a taken number

SO-D262 onto SO-D269, which exists: ARX3001, and both orders stay as they were.

In scope: `service` (ArxDynamoDbService).

```csharp
try
{
    await service.UpdateAsync(Renumber("SO-D262", "SO-D269"), AllowMove);
}
catch (ArxDatabaseException exception) when (exception.Code == ArxErrorCode.UniqueViolation)
{
    Console.WriteLine(exception.Message);
}
```

Check it in the database:

```sql
SELECT "SK", "total" FROM "crm" WHERE "PK" = 'CUSTOMER#C-D261' AND begins_with("SK", 'ORDER#SO-D26')
```

Expect: 2 items: ORDER#SO-D262 total 120 and ORDER#SO-D269 total 45.

