2

Currently, I am using ServiceStack.Aws v5.9.0 to communicate with DynamoDB. I have used PutItem for both creating and updating an item without anticipating data loss in case of concurrency handling.

public class Customer
{
   [HashKey]
   public int CustomerId { get; set; }
   [AutoIncrement]
   public int SubId { get; set; }
   public string CustomerType { get; set; }
   public string LastName { get; set; }
   public string FirstName { get; set; }
   ...//and hundreds of fields here
}

public class CustomerDynamo
{
   private readonly IPocoDynamo db;
   //Constructor
   public CustomerDynamo() 
   {
      var dynamoClient = new AmazonDynamoDBClient(_region);
      var entityType = typeof(Customer);
      var tableName = entityType.Name;
      entityType.AddAttributes(new AliasAttribute(name: tableName));
      db = new PocoDynamo(dynamoClient) { ConsistentRead = true }.RegisterTable(tableType: entityType);
   }

   public Customer Update(Customer customer)
   {
      customer.ModifiedDate = DateTime.UtcNow;
      db.PutItem(customer);
      return customer;
   }
}

The above Update method is called in every service/async task that needs to update the data of the customer. Refer to this article of AWS I decided to implement the Optimistic Locking to save my life from the issue of concurrency requests. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.VersionSupport.html

Assume that the VersionNumber will be the key for Optimistic Locking. So I added the VersionNumber into the Customer model.

public class Customer
{
   [HashKey]
   public int CustomerId { get; set; }
   [AutoIncrement]
   public int SubId { get; set; }
   public string CustomerType { get; set; }
   public string LastName { get; set; }
   public string FirstName { get; set; }
   ...//and hundreds of fields here
   [DynamoDBVersion]
   public int? VersionNumber { get; set; }
}
  1. The result is VersionNumber not updated while it should be automatically incremented. I think it is just because the PutItem will override the whole existing item. Is this correct?
  2. I think I need to change from PutItem to UpdateItem in the Update method. The question is how can I generate the expression dynamically to be used with the UpdateItem?

Thanks in advance for any help!

Updates:

Thanks @mythz for the useful information about DynamoDBVersion attribute. Then I tried to remove the DynamoDBVersion and using the UpdateExpression of PocoDynamo as below

public Customer Update(Customer customer)
{
   customer.ModifiedDate = DateTime.UtcNow;
   var expression = db.UpdateExpression<Customer>(customer.CustomerId).Set(() => customer);
   expression.ExpressionAttributeNames = new Dictionary<string, string>() 
   { 
      { "#Version", "VersionNumber" } 
   };
   expression.ExpressionAttributeValues = new Dictionary<string, AttributeValue>() 
   {
      { ":incr", new AttributeValue { N = "1" } },
      { ":zero", new AttributeValue { N = "0" } }
   };
   expression.UpdateExpression = "SET #Version = if_not_exists(#Version, :zero) + :incr";
   if (customer.VersionNumber.HasValue)
   {
      expression.Condition(c => c.VersionNumber == customer.VersionNumber);
   }
   var success = db.UpdateItem(expression);
}

But the changes are not saved except the VersionNumber

1 Answer 1

2

The [DynamoDBVersion] is an AWS Object Persistence Model attribute for usage with AWS's DynamoDBContext not for PocoDynamo. i.e. the only [DynamoDB*] attributes PocoDynamo utilizes are [DynamoDBHashKey] and [DynamoDBRangeKey] all other [DynamoDB*] attributes are intended for AWS's Object Persistence Model libraries.

When needed you can access AWS's IAmazonDynamoDB with:

var db = new PocoDynamo(awsDb);
var awsDb = db.DynamoDb;

Here are docs on PocoDynamo's UpdateItem APIs that may be relevant.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the information about [DynamoDB*] attributes. I tried to remove the [DynamoDBVersion] and use the UpdateExpression of PocoDynamo instead. I got the VersionNumber increased but the remaining properties of the customer are not updated. I use the expression as var expression = db.UpdateExpression<Customer>(customer.CustomerId).Set(() => customer); . Then update the item var success = db.UpdateItem(expression); . Did I do something wrong?
@KhoaTong You can only update specific fields in a new expression as shown the docs, it infers which properties to include in the query based on the expression, it has to be an expression not a model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.