Amazon DynamoDB · CreateMultiple
Create many records in one call
Many items in one call, in three scenarios: all stored together, none stored when one fails, and more than 100.
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.
1 All stored together
Three products in one transaction; the ids come back in the list's order.
Already in scope: service (ArxDynamoDbService)
IReadOnlyList<ArxRecordId> ids = await service.CreateMultipleAsync(new[]
{
Product("SKU-D201", "Rain jacket"),
Product("SKU-D202", "Fleece"),
Product("SKU-D203", "Beanie")
});
Console.WriteLine($"created {string.Join(", ", ids.Select(x => x.AsString()))}");Defined once in this sample.
private static ArxEntity Product(string sku, string name)
{
var product = new ArxEntity("product");
product["sku"] = sku;
product["name"] = name;
return product;
}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", "name" FROM "product" WHERE "sku" IN ['SKU-D201', 'SKU-D202', 'SKU-D203']Expect: 3 items.
2 One fails, none is stored
SKU-D201 exists already: the transaction is cancelled and SKU-D204 isn't stored either.
Already in scope: service (ArxDynamoDbService)
try
{
await service.CreateMultipleAsync(new[] { Product("SKU-D204", "Gloves"), Product("SKU-D201", "Rain jacket again") });
}
catch (ArxDatabaseException exception) when (exception.Code == ArxErrorCode.UniqueViolation)
{
Console.WriteLine(exception.Message);
}Defined once in this sample.
private static ArxEntity Product(string sku, string name)
{
var product = new ArxEntity("product");
product["sku"] = sku;
product["name"] = name;
return product;
}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" FROM "product" WHERE "sku" = 'SKU-D204'Expect: no items.
3 More than 100
150 items: refused as one call, stored in transactions of 100 when you allow it.
Already in scope: service (ArxDynamoDbService)
var products = Enumerable.Range(1, 150).Select(i => Product($"SKU-D3{i:000}", $"Bulk item {i}")).ToList();
try
{
await service.CreateMultipleAsync(products);
}
catch (ArxNotSupportedException exception)
{
Console.WriteLine(exception.Message);
}
var ids = await service.CreateMultipleAsync(products, new ArxDynamoWriteOptions { AllowPartial = true });
Console.WriteLine($"with AllowPartial: {ids.Count} created, in two transactions");Defined once in this sample.
private static ArxEntity Product(string sku, string name)
{
var product = new ArxEntity("product");
product["sku"] = sku;
product["name"] = name;
return product;
}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" FROM "product" WHERE "sku" IN ['SKU-D3001', 'SKU-D3150']Expect: 2 items.
Good to know
Up to 100 items go in one DynamoDB transaction: all or nothing. A transaction can't hold more, so more is refused, unless you allow them to go in transactions of 100, one after another.
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.CreateMultiple.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_CreateManyRecords().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.CreateMultiple.Basics;
/// <summary>
/// Many items in one call, in three scenarios: all stored together, none stored when one fails, and more than 100.
/// </summary>
/// <remarks>
/// Up to 100 items go in one DynamoDB transaction: all or nothing. A transaction can't hold more, so more is refused,
/// unless you allow them to go in transactions of 100, one after another.
/// </remarks>
public sealed class Basic1_CreateManyRecords : ISample
{
public string Name => "create-multiple-basics-1-create-many-records";
public string Title => "Create many records in one call";
public async Task RunAsync(SampleContext dbContext)
{
await Scenario1_AllStoredTogetherAsync(dbContext.Service);
await Scenario2_OneFailsAndNoneIsStoredAsync(dbContext.Service);
await Scenario3_MoreThan100Async(dbContext.Service);
}
private static ArxEntity Product(string sku, string name)
{
var product = new ArxEntity("product");
product["sku"] = sku;
product["name"] = name;
return product;
}
/// <summary>1. Three products in one transaction; the ids come back in the list's order.</summary>
private static async Task Scenario1_AllStoredTogetherAsync(ArxDynamoDbService service)
{
Step("1. All stored together");
IReadOnlyList<ArxRecordId> ids = await service.CreateMultipleAsync(new[]
{
Product("SKU-D201", "Rain jacket"),
Product("SKU-D202", "Fleece"),
Product("SKU-D203", "Beanie")
});
Show($"created {string.Join(", ", ids.Select(x => x.AsString()))}");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "sku", "name" FROM "product" WHERE "sku" IN ['SKU-D201', 'SKU-D202', 'SKU-D203']
* -- Expect: 3 items.
* ===========================================================
*/
}
/// <summary>2. SKU-D201 exists already: the transaction is cancelled and SKU-D204 isn't stored either.</summary>
private static async Task Scenario2_OneFailsAndNoneIsStoredAsync(ArxDynamoDbService service)
{
Step("2. One fails, none is stored");
try
{
await service.CreateMultipleAsync(new[] { Product("SKU-D204", "Gloves"), Product("SKU-D201", "Rain jacket again") });
}
catch (ArxDatabaseException exception) when (exception.Code == ArxErrorCode.UniqueViolation)
{
ShowError(exception);
}
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "sku" FROM "product" WHERE "sku" = 'SKU-D204'
* -- Expect: no items.
* ===========================================================
*/
}
/// <summary>3. 150 items: refused as one call, stored in transactions of 100 when you allow it.</summary>
private static async Task Scenario3_MoreThan100Async(ArxDynamoDbService service)
{
Step("3. More than 100");
var products = Enumerable.Range(1, 150).Select(i => Product($"SKU-D3{i:000}", $"Bulk item {i}")).ToList();
try
{
await service.CreateMultipleAsync(products);
}
catch (ArxNotSupportedException exception)
{
ShowError(exception);
}
var ids = await service.CreateMultipleAsync(products, new ArxDynamoWriteOptions { AllowPartial = true });
Show($"with AllowPartial: {ids.Count} created, in two transactions");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "sku" FROM "product" WHERE "sku" IN ['SKU-D3001', 'SKU-D3150']
* -- Expect: 2 items.
* ===========================================================
*/
}
}
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. All stored together
created SKU-D201, SKU-D202, SKU-D203
> 2. One fails, none is stored
caught ArxDatabaseException: ARX3001 UniqueViolation: CreateMultiple of 'product': item 1: an item with the same key already exists. Nothing was written.
> 3. More than 100
caught ArxNotSupportedException: ARX8001 NotSupported: CreateMultiple of 'product' writes 150 items, and DynamoDB's transactions hold at most 100, so ARX can't write them all or nothing. Write at most 100 at a time, or pass new ArxDynamoWriteOptions { AllowPartial = true } to send them in transactions of 100, one after another.
with AllowPartial: 150 created, in two transactions