Skip to content

Batch Operations

Mark Lauter edited this page Jun 2, 2026 · 7 revisions

Batch Operations

Overview

Batch operations read or write multiple items in a single call, potentially across multiple tables. BatchWriteItemAsync runs in a single SQLite transaction (all-or-nothing). BatchGetItemAsync reads each key sequentially on a shared connection — items reflect the state at read time, not a single transactional snapshot. See Batch Operations in the AWS docs.

BatchGetItemAsync

Retrieves up to 100 items from one or more tables in a single call.

Signatures

Task<BatchGetItemResponse> BatchGetItemAsync(BatchGetItemRequest request, CancellationToken ct = default)
Task<BatchGetItemResponse> BatchGetItemAsync(Dictionary<string, KeysAndAttributes> requestItems, CancellationToken ct = default)
Task<BatchGetItemResponse> BatchGetItemAsync(Dictionary<string, KeysAndAttributes> requestItems, ReturnConsumedCapacity returnConsumedCapacity, CancellationToken ct = default)

Parameters

  • RequestItems (required) — dictionary of table name to keys and optional projection
    • Keys — list of primary keys to retrieve
    • ProjectionExpression — attributes to return (per table)
    • ExpressionAttributeNames — name substitutions (per table)

Limits

  • Maximum 100 items total across all tables
  • At least 1 table must be specified

Example

var response = await client.BatchGetItemAsync(new BatchGetItemRequest
{
    RequestItems = new Dictionary<string, KeysAndAttributes>
    {
        ["Users"] = new KeysAndAttributes
        {
            Keys =
            [
                new Dictionary<string, AttributeValue>
                {
                    ["UserId"] = new() { S = "user-1" }
                },
                new Dictionary<string, AttributeValue>
                {
                    ["UserId"] = new() { S = "user-2" }
                }
            ],
            ProjectionExpression = "UserId, #n",
            ExpressionAttributeNames = new Dictionary<string, string>
            {
                ["#n"] = "Name"
            }
        },
        ["Orders"] = new KeysAndAttributes
        {
            Keys =
            [
                new Dictionary<string, AttributeValue>
                {
                    ["CustomerId"] = new() { S = "user-1" },
                    ["OrderId"] = new() { S = "order-1" }
                }
            ]
        }
    }
});

// Results organized by table name
var users = response.Responses["Users"];
var orders = response.Responses["Orders"];

Response

Field Description
Responses Dictionary of table name to list of items
UnprocessedKeys Always empty (DynamoDbLite processes all keys)

Parity notes

  • UnprocessedKeys is always an empty dictionary — DynamoDbLite never partially fails
  • Throws ResourceNotFoundException if any requested table does not exist — the entire call is rejected before any reads occur
  • TTL-expired items are filtered out
  • ConsistentRead is accepted per table but has no effect — all reads use the same SQLite snapshot
  • ProjectionExpression is applied in memory after retrieval; all attributes are read from SQLite regardless of projection (no behavioral impact, only performance)
  • ReturnConsumedCapacity is accepted but ignored — the response never includes capacity data

BatchWriteItemAsync

Writes (put or delete) up to 25 items across one or more tables in a single call. The 25-item cap is the default and is configurable — see Limits.

Signatures

Task<BatchWriteItemResponse> BatchWriteItemAsync(BatchWriteItemRequest request, CancellationToken ct = default)
Task<BatchWriteItemResponse> BatchWriteItemAsync(Dictionary<string, List<WriteRequest>> requestItems, CancellationToken ct = default)

Parameters

  • RequestItems (required) — dictionary of table name to list of write requests
    • Each WriteRequest contains either a PutRequest (with Item) or a DeleteRequest (with Key)

Limits

  • Maximum 25 operations total across all tables by default. Raise or lower the cap with MaxBatchWriteItems — handy for seeding more than 25 rows per call in tests
  • Duplicate keys (same table + PK + SK) are rejected
  • At least 1 table must be specified

Example

await client.BatchWriteItemAsync(new BatchWriteItemRequest
{
    RequestItems = new Dictionary<string, List<WriteRequest>>
    {
        ["Users"] =
        [
            new WriteRequest
            {
                PutRequest = new PutRequest
                {
                    Item = new Dictionary<string, AttributeValue>
                    {
                        ["UserId"] = new() { S = "user-1" },
                        ["Name"] = new() { S = "Alice" }
                    }
                }
            },
            new WriteRequest
            {
                PutRequest = new PutRequest
                {
                    Item = new Dictionary<string, AttributeValue>
                    {
                        ["UserId"] = new() { S = "user-2" },
                        ["Name"] = new() { S = "Bob" }
                    }
                }
            },
            new WriteRequest
            {
                DeleteRequest = new DeleteRequest
                {
                    Key = new Dictionary<string, AttributeValue>
                    {
                        ["UserId"] = new() { S = "user-3" }
                    }
                }
            }
        ]
    }
});

Response

Field Description
UnprocessedItems Always empty (DynamoDbLite processes all items)

Behavior

  • All operations execute in a single SQLite transaction (all-or-nothing)
  • Secondary indexes are maintained for all puts and deletes
  • TTL epochs are computed for put operations if TTL is enabled
  • Table statistics (item count, size) are updated per affected table

Parity notes

  • UnprocessedItems is always empty — no partial failures
  • Throws ResourceNotFoundException if any requested table does not exist — the entire batch is rejected before any writes occur
  • No ConditionExpression support on individual write requests (matches DynamoDB; use Transactions for conditional writes)
  • Duplicate key detection happens before any writes — the entire batch is rejected if duplicates are found
  • ReturnConsumedCapacity is accepted but ignored — the response never includes capacity data
  • The 25-operation cap matches DynamoDB but is configurable via MaxBatchWriteItems; raising it lets a single call exceed what real DynamoDB accepts

Next steps

  • Performance — batching is the top write-throughput lever; it amortizes per-operation overhead across the whole batch
  • Transactions — all-or-nothing multi-item operations with conditions

Clone this wiki locally