Amazon DynamoDB · UpdateMultiple
Update many records in one call
Many items in one call, all or nothing, in two scenarios: a different price for each product, and a list with one SKU no item has, where none of them changes.
Set up for this page
The scenarios build on the sample application: SampleContext.cs (the dbContext every sample is given); SampleOutput.cs (Step and Show, which print); SampleContext.Application.cs (dbContext.Service, the application's ARX service); SampleModel.cs (the DynamoDB layout and the schema catalog); SampleContext.Direct.cs (dbContext.Direct); DynamoDirectHelper.cs (the checks behind dbContext.Direct).
dbContext.Direct is the samples' own checking code on the plain driver, not part of ARX: leave it out of your application.
Before scenario 1 the sample runs this, so the service and the rows the scenarios use are there:
var products = new[] { "SKU-D271", "SKU-D272", "SKU-D273" }.Select(sku =>
{
var product = new ArxEntity("product");
product["sku"] = sku;
product["name"] = $"Trail sock {sku}";
product["price"] = 12.00m;
return product;
}).ToList();
var ids = await service.CreateMultipleAsync(products);1 A price per product
One entity per item, each with its own price, in one transaction.
Already in scope: service (ArxDynamoDbService), ids (IReadOnlyList<ArxRecordId>)
var changes = new List<ArxEntity>();
for (var i = 0; i < ids.Count; i++)
{
var change = new ArxEntity("product") { RecordId = ids[i] };
change["price"] = 10.00m + i;
changes.Add(change);
}
int changed = await service.UpdateMultipleAsync(changes);
Console.WriteLine($"{changed} items changed in one call");Check it in the database
A PartiQL statement: run it in NoSQL Workbench, or with aws dynamodb execute-statement --statement, after the code has run.
SELECT "sku", "price" FROM "product" WHERE "sku" IN ['SKU-D271', 'SKU-D272', 'SKU-D273']Expect: 3 items, price 10, 11, 12.
2 All or nothing
SKU-D279 is no item: RecordNotFound, and SKU-D271 keeps its price too.
Already in scope: service (ArxDynamoDbService)
var first = new ArxEntity("product");
first["sku"] = "SKU-D271";
first["price"] = 99.00m;
var missing = new ArxEntity("product");
missing["sku"] = "SKU-D279";
missing["price"] = 99.00m;
try
{
await service.UpdateMultipleAsync(new[] { first, missing });
}
catch (ArxException exception) when (exception.Code == ArxErrorCode.RecordNotFound)
{
Console.WriteLine(exception.Message);
}Check it in the database
A PartiQL statement: run it in NoSQL Workbench, or with aws dynamodb execute-statement --statement, after the code has run.
SELECT "sku", "price" FROM "product" WHERE "sku" IN ['SKU-D271', 'SKU-D279']Expect: 1 item, SKU-D271, price 10 (not 99).
Good to know
The updates go as one TransactWriteItems, each conditional on its item existing: at most 100 items in a call (more is ARX8001 unless AllowPartial). Each entity writes only the attributes it sets.
Run the complete sample
The code above comes from one program, built in a fresh project and run against the database. To run it yourself, here is every file and step.
The program, its files and how to run it
Run it locally
- .NET SDK: .NET SDK 10.0.100 or later 10.0.x (target
net10.0). - Create the project:
Terminal dotnet new console -n ArxSample -f net10.0 cd ArxSample - Install the packages:
Terminal dotnet add package ARX.SDK.DynamoDb --version 1.0.0-rc.1 - Database: a Amazon DynamoDB, or DynamoDB Local for development (tested with DynamoDB Local 2.5.2) database with the sample schema.
- Configuration: set
ARX_SAMPLES_DYNAMODBto its connection string. Nothing is hard-coded. - Source code: add the files of the sample application this sample uses (
SampleContext.cs,SampleOutput.cs,SampleContext.Application.cs,SampleModel.cs,SampleContext.Direct.cs,DynamoDirectHelper.cs), then replaceProgram.csand add the other file below, with the file names shown. - Run it:
Terminal dotnet run - Expected output: below.
The files
Runs the sample. Generated for this page; it reads the connection string from the environment and first remakes the sample database from sample-schema.json.
using ArxSamples.DynamoDb;
using ArxSamples.DynamoDb.Operations.UpdateMultiple.Basics;
// The connection string comes from the environment, never from the code (see "Configure the connection").
var connectionString = Environment.GetEnvironmentVariable("ARX_SAMPLES_DYNAMODB")
?? throw new InvalidOperationException("Set the ARX_SAMPLES_DYNAMODB environment variable to your Amazon DynamoDB connection string.");
var dbContext = new SampleContext(connectionString);
// Every run starts from the sample data: this deletes and makes again what sample-schema.json lists
// (save the file in the project folder, see Get started).
await dbContext.Direct.ResetAsync();
await new Basic1_UpdateManyRecords().RunAsync(dbContext);
The sample, as it is in the repository.
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Services;
using static ArxSamples.DynamoDb.SampleOutput;
namespace ArxSamples.DynamoDb.Operations.UpdateMultiple.Basics;
/// <summary>
/// Many items in one call, all or nothing, in two scenarios: a different price for each product, and a list with one
/// SKU no item has, where none of them changes.
/// </summary>
/// <remarks>
/// The updates go as one <c>TransactWriteItems</c>, each conditional on its item existing: at most 100 items in a call
/// (more is ARX8001 unless <c>AllowPartial</c>). Each entity writes only the attributes it sets.
/// </remarks>
public sealed class Basic1_UpdateManyRecords : ISample
{
public string Name => "update-multiple-basics-1-update-many-records";
public string Title => "Update many records in one call";
public async Task RunAsync(SampleContext dbContext)
{
var products = new[] { "SKU-D271", "SKU-D272", "SKU-D273" }.Select(sku =>
{
var product = new ArxEntity("product");
product["sku"] = sku;
product["name"] = $"Trail sock {sku}";
product["price"] = 12.00m;
return product;
}).ToList();
var ids = await dbContext.Service.CreateMultipleAsync(products);
await Scenario1_APricePerProductAsync(dbContext.Service, ids);
await Scenario2_AllOrNothingAsync(dbContext.Service);
}
/// <summary>1. One entity per item, each with its own price, in one transaction.</summary>
private static async Task Scenario1_APricePerProductAsync(ArxDynamoDbService service, IReadOnlyList<ArxRecordId> ids)
{
Step("1. A price per product");
var changes = new List<ArxEntity>();
for (var i = 0; i < ids.Count; i++)
{
var change = new ArxEntity("product") { RecordId = ids[i] };
change["price"] = 10.00m + i;
changes.Add(change);
}
int changed = await service.UpdateMultipleAsync(changes);
Show($"{changed} items changed in one call");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "sku", "price" FROM "product" WHERE "sku" IN ['SKU-D271', 'SKU-D272', 'SKU-D273']
* -- Expect: 3 items, price 10, 11, 12.
* ===========================================================
*/
}
/// <summary>2. SKU-D279 is no item: RecordNotFound, and SKU-D271 keeps its price too.</summary>
private static async Task Scenario2_AllOrNothingAsync(ArxDynamoDbService service)
{
Step("2. All or nothing");
var first = new ArxEntity("product");
first["sku"] = "SKU-D271";
first["price"] = 99.00m;
var missing = new ArxEntity("product");
missing["sku"] = "SKU-D279";
missing["price"] = 99.00m;
try
{
await service.UpdateMultipleAsync(new[] { first, missing });
}
catch (ArxException exception) when (exception.Code == ArxErrorCode.RecordNotFound)
{
ShowError(exception);
}
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "sku", "price" FROM "product" WHERE "sku" IN ['SKU-D271', 'SKU-D279']
* -- Expect: 1 item, SKU-D271, price 10 (not 99).
* ===========================================================
*/
}
}
Expected output
What dotnet run printed when the sample was verified, on a freshly created sample schema. Ids differ when the tables already hold rows.
> 1. A price per product
3 items changed in one call
> 2. All or nothing
caught ArxDatabaseException: ARX2002 RecordNotFound: UpdateMultiple of 'product': item 1: no item has the key. Nothing was written.