David Pfeffer
David Pfeffer

Reputation: 39871

Avoiding the new upsert in Azure Table Storage

Steve Marx writes about new extension methods to perform upserts in Azure Table Storage as part of the new storage protocol version here:

http://blog.smarx.com/posts/extension-methods-for-the-august-storage-features

However, what if I want to do the original operation of unconditional-merge-or-throw, rather than an upsert. I want to merge an object, updating a single field, but throw if the entity doesn't exist rather than create a new entity that contains only the properties I'm merging.

Is this possible? Note that I want to use upsert elsewhere, so I've taken to having IoC provide me with contexts created from GetDataServiceContext2011 instead of GetDataServiceContext. I suppose I could alternate between the two, but that won't help when the Azure team updates the official libraries.

According to MSDN:

The Insert Or Merge Entity operation uses the MERGE verb and must be called using the 2011-08-18 version or newer. In addition, it does not use the If-Match header. These attributes distinguish this operation from the Update Entity operation, though the request body is the same for both operations.

So, how do I get the storage library to emit a wildcard If-Match on save rather than emit no If-Match at all?

Upvotes: 2

Views: 2526

Answers (1)

user94559
user94559

Reputation: 60153

Just use AttachTo with an asterisk for an etag. That will result in an If-Match: *. Here's a complete working example:

class Entity : TableServiceEntity
{
    public string Text { get; set; }
    public Entity() { }
    public Entity(string rowkey) : base(string.Empty, rowkey) { }
}
class Program
{
    static void Update(CloudStorageAccount account)
    {
        var ctx = account.CreateCloudTableClient().GetDataServiceContext();

        var entity = new Entity("foo") { Text = "bar" };
        ctx.AttachTo("testtable", entity, "*");
        ctx.UpdateObject(entity);
        ctx.SaveChangesWithRetries();
    }

    static void Main(string[] args)
    {
        var account = CloudStorageAccount.Parse(args[0]);
        var tables = account.CreateCloudTableClient();
        tables.CreateTableIfNotExist("testtable");
        var ctx = tables.GetDataServiceContext();

        try { Update(account); } catch (Exception e) { Console.WriteLine("Exception (as expected): " + e.Message); }

        ctx.AddObject("testtable", new Entity("foo") { Text = "foo" });
        ctx.SaveChangesWithRetries();

        try { Update(account); } catch (Exception e) { Console.WriteLine("Unexpected exception: " + e.Message); }

        Console.WriteLine("Now text is: " + tables.GetDataServiceContext().CreateQuery<Entity>("testtable").Where(e => e.PartitionKey == string.Empty && e.RowKey == "foo").Single().Text);
        tables.DeleteTableIfExist("testtable");
    }
}

Upvotes: 5

Related Questions