# CreateMultiple with ARX.SDK on Amazon DynamoDB

## What a CreateMultiple does

| Rule | On DynamoDB |
|---|---|
| Many items | CreateMultiple is all or nothing, in one `TransactWriteItems` of up to 100 items; more is ARX8001 unless `new ArxDynamoWriteOptions { AllowPartial = true }` (transactions of 100, one after another) |

## The samples

Every CreateMultiple 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.

### Create many records in one call

Basics 1 of CreateMultiple.

Many items in one call, in three scenarios: all stored together, none stored when one fails, and more than 100.

Good to know:

Up to 100 items go in one DynamoDB transaction: all or nothing. A transaction can't hold more, so more is refused, unless you allow them to go in transactions of 100, one after another.

Usings:

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

#### 1. All stored together

Three products in one transaction; the ids come back in the list's order.

In scope: `service` (ArxDynamoDbService).

```csharp
IReadOnlyList<ArxRecordId> ids = await service.CreateMultipleAsync(new[]
{
    Product("SKU-D201", "Rain jacket"),
    Product("SKU-D202", "Fleece"),
    Product("SKU-D203", "Beanie")
});

Console.WriteLine($"created {string.Join(", ", ids.Select(x => x.AsString()))}");
```

Defined in the sample, used above:

```csharp
private static ArxEntity Product(string sku, string name)
{
    var product = new ArxEntity("product");
    product["sku"] = sku;
    product["name"] = name;
    return product;
}
```

Check it in the database:

```sql
SELECT "sku", "name" FROM "product" WHERE "sku" IN ['SKU-D201', 'SKU-D202', 'SKU-D203']
```

Expect: 3 items.

#### 2. One fails, none is stored

SKU-D201 exists already: the transaction is cancelled and SKU-D204 isn't stored either.

In scope: `service` (ArxDynamoDbService).

```csharp
try
{
    await service.CreateMultipleAsync(new[] { Product("SKU-D204", "Gloves"), Product("SKU-D201", "Rain jacket again") });
}
catch (ArxDatabaseException exception) when (exception.Code == ArxErrorCode.UniqueViolation)
{
    Console.WriteLine(exception.Message);
}
```

Check it in the database:

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

Expect: no items.

#### 3. More than 100

150 items: refused as one call, stored in transactions of 100 when you allow it.

In scope: `service` (ArxDynamoDbService).

```csharp
var products = Enumerable.Range(1, 150).Select(i => Product($"SKU-D3{i:000}", $"Bulk item {i}")).ToList();

try
{
    await service.CreateMultipleAsync(products);
}
catch (ArxNotSupportedException exception)
{
    Console.WriteLine(exception.Message);
}

var ids = await service.CreateMultipleAsync(products, new ArxDynamoWriteOptions { AllowPartial = true });
Console.WriteLine($"with AllowPartial: {ids.Count} created, in two transactions");
```

Check it in the database:

```sql
SELECT "sku" FROM "product" WHERE "sku" IN ['SKU-D3001', 'SKU-D3150']
```

Expect: 2 items.

### Spread a hot partition with write sharding

Advanced case 1 of CreateMultiple.

Write sharding for a hot partition, in two scenarios: page views of one page spread over four partitions, and read back as one partition, in order.

Good to know:

The model declares it once: `.WriteSharding("page_view", shards: 4, by: "viewed_at")`. ARX adds `#SHARD#n` to the partition key, n from a stable hash of `viewed_at`, so one view is still found by its key; a read of the whole page asks the four shards and merges them by the sort key.

Usings:

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

#### 1. Spread the writes

Twenty views of the home page, written over four shards.

In scope: `service` (ArxDynamoDbService).

```csharp
var views = Enumerable.Range(0, 20).Select(i =>
{
    var view = new ArxEntity("page_view");
    view["page"] = "home-d801";
    view["viewed_at"] = $"2026-11-09T10:00:{i:00}Z";
    view["visitor"] = $"v{i % 7}";
    return view;
}).ToList();

await service.CreateMultipleAsync(views);

Console.WriteLine("20 views written");
```

Check it in the database:

```sql
SELECT "PK" FROM "events" WHERE "PK" IN ['PAGE#home-d801#SHARD#0', 'PAGE#home-d801#SHARD#1', 'PAGE#home-d801#SHARD#2', 'PAGE#home-d801#SHARD#3']
```

Expect: 20 items, under more than one of the four shard keys.

#### 2. Read them back as one

The page's views in time order, a page of 8 at a time: every view once.

In scope: `service` (ArxDynamoDbService).

```csharp
var seen = new List<string>();
string? cookie = null;

do
{
    var query = new ArxQueryExpression("page_view");
    query.Criteria.AddCondition("page", ArxConditionOperator.Equal, "home-d801");
    query.AddOrder("viewed_at", ArxOrderType.Ascending);
    query.PageInfo = new ArxPagingInfo { Count = 8, PagingCookie = cookie };
    var page = await service.RetrieveMultipleAsync(query);
    seen.AddRange(page.Entities.Select(x => (string)x["viewed_at"]!));
    cookie = page.PagingCookie;
}
while (cookie != null);

Console.WriteLine($"read {seen.Count} views, first {seen[0]}, last {seen[^1]}");
```

Check it in the database:

```sql
SELECT "viewed_at" FROM "events" WHERE "page" = 'home-d801'
```

Expect: 20 items.

