Donuts
Donuts

Reputation: 2241

How can I get DynamoDbContext to throw an exception on Save if an item hash key already exists

I'm creating a new item in DynamoDB and I want it to throw an exception if the hash key already exists. I want this, because I don't want to have to query for an item before the insert for performance reasons, as it is extremely unlikely that my key will collide. but if it does i want to retry with a new key. Currently when I call Save via the object level api, it just updates the record.

public class DynamoService
{
    private readonly IDynamoDBContext _dbContext;
    private readonly IAmazonDynamoDB _dynamoClient;

    public DynamoService(IAmazonDynamoDB dynamoClient, IDynamoDBContext dbContext )
    {
        _dynamoClient = dynamoClient;
        _dbContext = dbContext;
    }

    public virtual async Task Save<T>(T item) where T : new()
    {
        await _dbContext.SaveAsync(item);
    }
}

Upvotes: 4

Views: 2098

Answers (2)

d03090
d03090

Reputation: 364

This is also possible with the .NET Object Persistence model by using "Optimistic Locking" (described here)

Inside your class you have to mark one property for being used as a VersionNumber.

public class DynamoDbItem
{
   [DynamoDBHashKey]
   public string SomeId { get; set; }       
    
   // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.VersionSupport.html
   [DynamoDBVersion]
   public int? VersionNumber { get; set; }
}

During saving you need to specify that you want to perform a version check.

public virtual async Task Save<T>(T item) where T : new()
{
    await _dbContext.SaveAsync(item, new DynamoDBOperationConfig
            {
               SkipVersionCheck = false
            });
}

For creating the item (saving for the first time) set the VersionNumber = null. The item will be saved in DynamoDB with VersionNumber = 0. Then if you try to create an item with the same PrimaryKey (and SortKey) VersionNumber = null (from C#) will not match VersionNumber = 0 (saved in DynamoDB) and SaveAsync will throw an exception.

Note: This only works if you specify SkipVersionCheck = false either as DynamoDBOperationConfig or as DynamoDBContextConfig on _dbContext.

Upvotes: 1

Brian Winant
Brian Winant

Reputation: 3035

Add a conditional expression using attribute_not_exists to your PutItem request.

See the section "Preventing Overwrites of an Existing Item" in https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html

The conditional expression will cause a ConditionalCheckFailedException if the item already exists, which you can catch and then do your retry logic

Upvotes: 1

Related Questions