3.
Updating entities
When deleting an object
using the StorageClient library, you need to keep track of the objects
to be deleted in the context object for the Products table. You can use
similar logic to update objects in your application.
Here’s an example:
var shirtContext = new ProductContext();
shirtToUpdate = (from item in shirtContext.Products
where item.PartitionKey == "Shirts"
&& item.RowKey == "RedShirt"
select item).First();
shirtToUpdate.Description = "I have been modified";
shirtContext.UpdateObject(shirtToUpdate);
shirtContext.SaveChanges(saveOptions);
The preceding code retrieves the RedShirt
entity from the Shirts partition in
the Products table. The code then modifies the description of the
entity and saves the changes back to the Products table.
Merging Data
By default, the SaveChanges
method will merge
any changes made to the object back to the entity stored in the Table
service, rather than performing a replacement update.
Before we can explain what
this means, let’s look at an extract of Atom XML that describes the
entity held in the Table service:
<content type="application/xml">
<m:properties>
<d:Description>A Red Shirt</d:Description>
<d:Name>Red Shirt</d:Name>
<d:PartitionKey>Shirts</d:PartitionKey>
<d:RowKey>RedShirt</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
</m:properties>
</content>
By choosing to merge the data,
you can efficiently send data back to the Table service by only sending
the modified data instead of the full entity. Table 1
shows how this would work in three scenarios:
Remote— A remote copy of the entity is stored in the Products
table.
Local— A local copy of the entity is used.
Merged— The changes in the local version of the entity are merged
with the remote version.
Table 1. Merging data with updates
Scenario | Partition key | Row key | Name | Description |
---|
Remote | Shirts | RedShirt | RedShirt | A Red Shirt |
Local | Shirts | RedShirt | RedShirt | A Pink Shirt |
Merged | Shirts | RedShirt | RedShirt | A Pink Shirt |
As you can see in table 1, the only property that has changed for the entity is the
description. This means that the client application doesn’t need to send
back the name property in the Atom XML describing the entity. The
following extract of the Atom XML describes what would be returned to
the Table service as part of the merge operation:
<content type="application/xml">
<m:properties>
<d:Description>A Pink Shirt</d:Description>
</m:properties>
</content>
If you need to replace the
entity stored in the Table service with your local version rather than
performing a merge, you can use the following setting in your client
code:
shirtContext.SaveChangesDefaultOptions =
SaveChangesOptions.ReplaceOnUpdate;
In this case, the Atom XML
sent using the REST API would contain the full description of the entity
rather than just the changed properties.
Using the REST API to
Merge or Update
When you use the REST API to
update or merge data, you’re really using a combination of the delete
and insert REST API functions.
The URI to update or merge the
local entity back to the Table storage is the same URI as for the
delete operation:
http://silverlightukstorage.table.core.windows.net/Products(PartitionKey='Shirts', RowKey='RedShirt')
As you can see, the URI needs
to specify the PartitionKey and RowKey of the entity being modified. Depending on the operation
you’re performing, you should set the HTTP verb to either MERGE
or PUT. Finally, the body of the HTTP
request should be set to the AtomPub XML document that describes the
entity (this is the same as the XML used to create the entity).
If you wish to modify the
console application from section
1 of this article to merge instead of insert, you
would need to change the URI and HTTP verbs in the code.
Finally, you would need to add a new If-Match header to the request. This header is used to
ensure that the data held in the remote version of the entity has not
changed since you grabbed the local version. If you wish to ensure that
data is only modified if the data is unchanged, you should set the If-Match header to the e-tag that was originally returned
with the entity.
If you wish to perform an
unconditional update, the value of the If-Match
header should be set to "*".
In this section, you’ve
learned how to perform inserts, updates, and deletes against your
entities. But you’re unlikely to work with single entities, so it’s time
to learn about some of the complications of updating data—batching and
transactions.