-
Notifications
You must be signed in to change notification settings - Fork 0
Transactions
DynamoDbLite supports transactional reads and writes with all-or-nothing semantics. Transactions evaluate conditions before executing any writes, and the entire operation is wrapped in a single SQLite transaction. See DynamoDB Transactions in the AWS docs.
Executes up to 100 write actions atomically. All conditions are evaluated first; if any fail, no writes occur.
Task<TransactWriteItemsResponse> TransactWriteItemsAsync(
TransactWriteItemsRequest request, CancellationToken cancellationToken = default)- TransactItems (required) — list of 1-100 actions
- ClientRequestToken — idempotency token (10-minute cache TTL)
Each TransactWriteItem contains exactly one action:
| Action | Description | Supports ConditionExpression |
|---|---|---|
| Put | Write a complete item | Yes |
| Update | Apply an UpdateExpression | Yes |
| Delete | Remove an item by key | Yes |
| ConditionCheck | Validate a condition without modifying data | Yes (required) |
await client.TransactWriteItemsAsync(new TransactWriteItemsRequest
{
TransactItems =
[
new TransactWriteItem
{
Put = new Put
{
TableName = "Accounts",
Item = new Dictionary<string, AttributeValue>
{
["AccountId"] = new() { S = "acct-1" },
["Balance"] = new() { N = "1000" }
},
ConditionExpression = "attribute_not_exists(AccountId)"
}
},
new TransactWriteItem
{
Update = new Update
{
TableName = "Accounts",
Key = new Dictionary<string, AttributeValue>
{
["AccountId"] = new() { S = "acct-2" }
},
UpdateExpression = "SET Balance = Balance - :amount",
ConditionExpression = "Balance >= :amount",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
[":amount"] = new() { N = "500" }
}
}
},
new TransactWriteItem
{
ConditionCheck = new ConditionCheck
{
TableName = "Config",
Key = new Dictionary<string, AttributeValue>
{
["ConfigId"] = new() { S = "transfers-enabled" }
},
ConditionExpression = "#v = :true",
ExpressionAttributeNames = new Dictionary<string, string>
{
["#v"] = "Value"
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
[":true"] = new() { BOOL = true }
}
}
}
]
});- Validation — verify table existence, key schemas, item uniqueness
- Pre-read — load existing items for condition evaluation and updates
- Condition evaluation — evaluate all ConditionExpressions; collect failures
- Update expression application — apply UpdateExpressions to produce new items
- Write — execute all puts/deletes in a single SQLite transaction
If any condition fails, a TransactionCanceledException is thrown with per-action details:
try
{
await client.TransactWriteItemsAsync(request);
}
catch (TransactionCanceledException ex)
{
foreach (var reason in ex.CancellationReasons)
{
Console.WriteLine($"Code: {reason.Code}"); // "ConditionalCheckFailed" or "None"
Console.WriteLine($"Message: {reason.Message}");
// reason.Item contains the existing item if ReturnValuesOnConditionCheckFailure = ALL_OLD
}
}Each action supports ReturnValuesOnConditionCheckFailure:
-
NONE(default) — no item returned on failure -
ALL_OLD— returns the existing item in theCancellationReason.Itemfield
new TransactWriteItem
{
Put = new Put
{
TableName = "Users",
Item = myItem,
ConditionExpression = "attribute_not_exists(UserId)",
ReturnValuesOnConditionCheckFailure = "ALL_OLD"
}
}If ClientRequestToken is provided, the response is cached for 10 minutes. Subsequent requests with the same token return the cached response without re-executing the transaction. The cache lives in process memory and is cleaned lazily — expired entries are evicted only when a later request with a ClientRequestToken arrives, not on a background timer.
await client.TransactWriteItemsAsync(new TransactWriteItemsRequest
{
ClientRequestToken = "unique-request-id-123",
TransactItems = [/* ... */]
});- Minimum 1 action per transaction — an empty
TransactItemslist throwsAmazonDynamoDBException - Maximum 100 actions per transaction
- Each item can appear in at most one action (enforced by table + PK + SK uniqueness)
- Update actions require an
UpdateExpression
Retrieves up to 100 items atomically from one or more tables.
Task<TransactGetItemsResponse> TransactGetItemsAsync(
TransactGetItemsRequest request, CancellationToken cancellationToken = default)-
TransactItems (required) — list of 1-100
Getactions- TableName (required) — target table
- Key (required) — primary key
- ProjectionExpression — attributes to return
- ExpressionAttributeNames — name substitutions
var response = await client.TransactGetItemsAsync(new TransactGetItemsRequest
{
TransactItems =
[
new TransactGetItem
{
Get = new Get
{
TableName = "Users",
Key = new Dictionary<string, AttributeValue>
{
["UserId"] = new() { S = "user-1" }
}
}
},
new TransactGetItem
{
Get = new Get
{
TableName = "Orders",
Key = new Dictionary<string, AttributeValue>
{
["CustomerId"] = new() { S = "user-1" },
["OrderId"] = new() { S = "order-1" }
},
ProjectionExpression = "OrderId, #s, Total",
ExpressionAttributeNames = new Dictionary<string, string>
{
["#s"] = "Status"
}
}
}
]
});
// Responses are ordered to match the request
var user = response.Responses[0].Item; // may be null if not found
var order = response.Responses[1].Item;Each ItemResponse in Responses contains an Item (the retrieved attributes) or null if the item doesn't exist.
- Minimum 1
Getaction — an emptyTransactItemslist throwsAmazonDynamoDBException - Maximum 100
Getactions per call
- All conditions are evaluated atomically (single SQLite transaction)
-
ClientRequestTokenidempotency uses an in-memory cache with 10-minute TTL (not persisted across restarts) -
ReturnConsumedCapacityis accepted but has no effect — capacity tracking is out of scope - Index maintenance happens within the same transaction
ExecuteStatementAsync, BatchExecuteStatementAsync, and ExecuteTransactionAsync (PartiQL) throw NotSupportedException. PartiQL is out of scope for this emulator.
- API Parity — full compatibility matrix and behavioral differences
Repo · NuGet · API Parity
Getting started
Reference
- Table Operations
- Item Operations
- Query and Scan
- Batch Operations
- Transactions
- Secondary Indexes
- TTL
- Tags and Admin
- DI and Configuration
- Concurrency
- Performance
- API Parity
- FAQ
Recipes
- DynamoDBContext for tests
- xUnit per-test isolation
- ASP.NET Core integration test fixture
- Migrating tests off DynamoDB Local
Internals