Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
    }
}
like image 824
Donuts Avatar asked Oct 25 '25 00:10

Donuts


2 Answers

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

like image 86
Brian Winant Avatar answered Oct 27 '25 14:10

Brian Winant


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.

like image 30
d03090 Avatar answered Oct 27 '25 13:10

d03090



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!