For those looking for something more detailed, the following translates the Java snippets the question links to at https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-example.html into their C# equivalents.
Keep in mind that the original Java example is a contrived one. In a production environment, you would want to do things like separate business logic from writing to a console and separate the various parts of building a transaction into smaller methods to adhere to SRP.
Prerequisites
private const string CUSTOMER_TABLE_NAME = "Customers";
private const string CUSTOMER_PARTITION_KEY = "CustomerId";
private const string PRODUCT_TABLE_NAME = "ProductCatalog";
private const string PRODUCT_PARTITION_KEY = "ProductId";
private const string ORDER_PARTITION_KEY = "OrderId";
private const string ORDER_TABLE_NAME = "Orders";
- both the read and write Java examples assume method signatures taking two string parameters named
productKey
and orderId
- You'll need the following two using statements in your class:
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
Making an order
Validate the customer
var customerId = "09e8e9c8-ec48";
var customerItemKey = new Dictionary<string, AttributeValue>
{
{ CUSTOMER_PARTITION_KEY, new AttributeValue(customerId) }
};
var checkCustomerValid = new ConditionCheck()
{
TableName = CUSTOMER_TABLE_NAME,
Key = customerItemKey,
ConditionExpression = "attribute_exists(" + CUSTOMER_PARTITION_KEY + ")"
};
Update the product status
var productItemKey = new Dictionary<string, AttributeValue>
{
{ PRODUCT_PARTITION_KEY, new AttributeValue(productKey) }
};
var expressionAttributeValues = new Dictionary<string, AttributeValue>
{
{ ":new_status", new AttributeValue("SOLD") },
{ ":expected_status", new AttributeValue("IN_STOCK") }
};
var markItemSold = new Update()
{
TableName = PRODUCT_TABLE_NAME,
Key = productItemKey,
UpdateExpression = "SET ProductStatus = :new_status",
ExpressionAttributeValues = expressionAttributeValues,
ConditionExpression = "ProductStatus = :expected_status",
ReturnValuesOnConditionCheckFailure = ReturnValuesOnConditionCheckFailure.ALL_OLD
};
Create the order
var orderItem = new Dictionary<string, AttributeValue>
{
{ ORDER_PARTITION_KEY, new AttributeValue(orderId) },
{ PRODUCT_PARTITION_KEY, new AttributeValue(productKey) },
{ CUSTOMER_PARTITION_KEY, new AttributeValue(customerId) },
{ "OrderStatus", new AttributeValue("CONFIRMED") },
{ "OrderTotal", new AttributeValue("100") }
};
var createOrder = new Put()
{
TableName = ORDER_TABLE_NAME,
Item = orderItem,
ReturnValuesOnConditionCheckFailure = ReturnValuesOnConditionCheckFailure.ALL_OLD,
ConditionExpression = "attribute_not_exists(" + ORDER_PARTITION_KEY + ")"
};
Run the transaction
var actions = new List<TransactWriteItem>()
{
new TransactWriteItem() {ConditionCheck = checkCustomerValid },
new TransactWriteItem() { Update = markItemSold },
new TransactWriteItem() { Put = createOrder }
};
var placeOrderTransaction = new TransactWriteItemsRequest()
{
TransactItems = actions,
ReturnConsumedCapacity = ReturnConsumedCapacity.TOTAL
};
// Run the transaction and process the result.
try
{
_ = await client.TransactWriteItemsAsync(placeOrderTransaction);
Console.WriteLine("Transaction Successful");
}
catch (ResourceNotFoundException rnf)
{
Console.Error.WriteLine("One of the table involved in the transaction is not found" + rnf.Message);
}
catch (InternalServerErrorException ise)
{
Console.Error.WriteLine("Internal Server Error" + ise.Message);
}
catch (TransactionCanceledException tce)
{
Console.Error.WriteLine("Transaction Canceled " + tce.Message);
}
Reading the order details
var productItemKey = new Dictionary<string, AttributeValue>
{
{ PRODUCT_PARTITION_KEY, new AttributeValue(productKey) }
};
var orderKey = new Dictionary<string, AttributeValue>
{
{ ORDER_PARTITION_KEY, new AttributeValue(orderId) }
};
var readProductSold = new Get()
{
TableName = PRODUCT_TABLE_NAME,
Key = productItemKey
};
var readCreatedOrder = new Get()
{
TableName = ORDER_TABLE_NAME,
Key = orderKey
};
var getActions = new List<TransactGetItem>()
{
new TransactGetItem(){Get = readProductSold },
new TransactGetItem(){Get = readCreatedOrder}
};
var readCompletedOrder = new TransactGetItemsRequest()
{
TransactItems = getActions,
ReturnConsumedCapacity = ReturnConsumedCapacity.TOTAL
};
// Run the transaction and process the result.
try
{
var result = await client.TransactGetItemsAsync(readCompletedOrder);
Console.WriteLine(result.Responses);
}
catch (ResourceNotFoundException rnf)
{
Console.Error.WriteLine("One of the table involved in the transaction is not found" + rnf.Message);
}
catch (InternalServerErrorException ise)
{
Console.Error.WriteLine("Internal Server Error" + ise.Message);
}
catch (TransactionCanceledException tce)
{
Console.Error.WriteLine("Transaction Canceled" + tce.Message);
}