TableTransaction provides a helper class for building batch operations that can be executed atomically within a single partition.
Helper class to build a list of transaction actions for batch operations.
/**
* Helper class to build a list of transaction actions for batch operations.
* All operations in a transaction must target entities in the same partition.
*/
class TableTransaction {
/** List of actions to perform in a transaction */
readonly actions: TransactionAction[];
/**
* Creates a new transaction builder
* @param actions - Optional initial list of actions
*/
constructor(actions?: TransactionAction[]);
}Methods for adding different types of operations to the transaction.
/**
* Adds a create entity action to the transaction
* @param entity - The entity to create, must include partitionKey and rowKey
*/
createEntity<T extends object>(entity: TableEntity<T>): void;
/**
* Adds a delete entity action to the transaction
* @param partitionKey - The partition key of the entity to delete
* @param rowKey - The row key of the entity to delete
*/
deleteEntity(partitionKey: string, rowKey: string): void;
/**
* Adds an update entity action to the transaction
* @param entity - The entity to update, must include partitionKey, rowKey, and etag
* @param updateMode - Update mode: "Merge" (partial) or "Replace" (full), defaults to "Merge"
*/
updateEntity<T extends object>(entity: TableEntity<T>, updateMode?: UpdateMode): void;
/**
* Adds an upsert entity action to the transaction
* @param entity - The entity to upsert, must include partitionKey and rowKey
* @param updateMode - Update mode: "Merge" (partial) or "Replace" (full), defaults to "Merge"
*/
upsertEntity<T extends object>(entity: TableEntity<T>, updateMode?: UpdateMode): void;Tuple types representing the different actions that can be performed in a transaction.
/**
* Represents the Create or Delete Entity operation to be included in a Transaction request
*/
type CreateDeleteEntityAction = ["create" | "delete", TableEntity];
/**
* Represents the Update or Upsert Entity operation to be included in a Transaction request
*/
type UpdateEntityAction =
| ["update" | "upsert", TableEntity]
| ["update" | "upsert", TableEntity, "Merge" | "Replace"];
/**
* Represents the union of all the available transactional actions
*/
type TransactionAction = CreateDeleteEntityAction | UpdateEntityAction;
/**
* The different modes for Update and Upsert methods
* - Merge: Updates an entity by updating the entity's properties without replacing the existing entity.
* - Replace: Updates an existing entity by replacing the entire entity.
*/
type UpdateMode = "Merge" | "Replace";Usage Examples:
import { TableClient, TableTransaction, AzureNamedKeyCredential } from "@azure/data-tables";
const credential = new AzureNamedKeyCredential("accountName", "accountKey");
const tableClient = new TableClient("https://myaccount.table.core.windows.net", "Orders", credential);
// Create a transaction with multiple operations
const transaction = new TableTransaction();
// Add various operations to the transaction
transaction.createEntity({
partitionKey: "2023-09",
rowKey: "order1",
customerId: "customer1",
total: 99.99,
status: "pending"
});
transaction.updateEntity({
partitionKey: "2023-09",
rowKey: "order2",
etag: "existing-etag",
status: "completed"
}, "Merge");
transaction.upsertEntity({
partitionKey: "2023-09",
rowKey: "order3",
customerId: "customer2",
total: 149.99,
status: "processing"
}, "Replace");
transaction.deleteEntity("2023-09", "order4");
// Submit the entire transaction atomically
const result = await tableClient.submitTransaction(transaction.actions);
console.log(`Transaction completed with ${result.subResponses.length} operations`);
result.subResponses.forEach((response, index) => {
console.log(`Operation ${index + 1}: Status ${response.status}`);
if (response.error) {
console.log(` Error: ${response.error.message}`);
}
});Response structure returned when submitting a transaction.
interface TableTransactionResponse {
/** Collection of sub responses */
subResponses: TableTransactionEntityResponse[];
/** Main Transaction request status code */
status: number;
/** Gets a specific response given a row key */
getResponseForEntity: (rowKey: string) => TableTransactionEntityResponse | undefined;
}
interface TableTransactionEntityResponse {
/** Entity's etag */
etag?: string;
/** Entity's rowKey */
rowKey?: string;
/** Sub-response status */
status: number;
}Partition Key Requirements:
Transaction Limits:
Error Handling:
subResponse.status codes for operation-specific resultsPerformance Considerations:
// Example: Error handling and validation
const transaction = new TableTransaction();
// Validate all entities target the same partition
const targetPartition = "2023-09";
const entities = [
{ partitionKey: targetPartition, rowKey: "1", data: "value1" },
{ partitionKey: targetPartition, rowKey: "2", data: "value2" },
{ partitionKey: targetPartition, rowKey: "3", data: "value3" }
];
// Add operations with validation
entities.forEach(entity => {
if (entity.partitionKey !== targetPartition) {
throw new Error(`Entity ${entity.rowKey} has wrong partition key`);
}
transaction.createEntity(entity);
});
try {
const result = await tableClient.submitTransaction(transaction.actions);
// Check for any failed operations
const failures = result.subResponses.filter(r => r.status >= 400);
if (failures.length > 0) {
console.log(`${failures.length} operations failed in transaction`);
failures.forEach((failure, index) => {
console.log(`Failed operation ${index}: ${failure.error?.message}`);
});
} else {
console.log("All operations succeeded");
}
} catch (error) {
console.error("Transaction failed:", error.message);
}You can also build transactions manually without the helper class:
// Manual transaction action construction using tuple format
const actions: TransactionAction[] = [
["create", {
partitionKey: "manual",
rowKey: "entity1",
value: "created manually"
}],
["delete", {
partitionKey: "manual",
rowKey: "entity2"
}],
["update", {
partitionKey: "manual",
rowKey: "entity3",
etag: "existing-etag",
value: "updated manually"
}, "Replace"]
];
const result = await tableClient.submitTransaction(actions);interface TableEntity<T extends object = Record<string, unknown>> {
/** Required partition key for entity grouping */
partitionKey: string;
/** Required row key for unique identification within partition */
rowKey: string;
/** Entity tag for concurrency control */
etag?: string;
}
interface HttpResponse {
/** HTTP status code */
status: number;
/** Response headers */
headers: { [key: string]: string };
/** Response body */
body?: any;
}