[This is prerelease documentation and is subject to change in future releases.]
The 2009-04-14 version of the Table service supports batch transactions on entities that are in the same table and belong to the same partition group. Multiple Insert Entity, Update Entity, Merge Entity, and Delete Entity operations are supported within a single transaction.
You can perform entity group transactions either via REST or by using the .NET Client Library for ADO.NET Data Services.
Note |
|---|
| Entity group transactions are not currently supported by the Windows® Azure™ SDK development environment, including development storage and the Storage Client sample library. |
Requirements for Entity Group Transactions
An entity group transaction must meet the following requirements:
- All entities subject to operations as part of the transaction must have the same PartitionKey value.
- An entity can appear only once in the transaction, and only one operation may be performed against it.
- The transaction can include at most 100 entities, and its total payload may be no more than 4 MB in size.
Table Service Support for ADO.NET Data Services Batch Requests
The semantics for entity group transactions are defined by the ADO.NET Data Services Specifications. The ADO.NET Data Services specification defines the following concepts for batch requests:
- A change set is a group of one or more insert, update, or delete operations.
- A batch is a container of operations, including one or more change sets and query operations.
The Table service supports a subset of the functionality defined by ADO.NET Data Services:
- The Table service supports only a single change set within a batch. The change set can include multiple insert, update, and delete operations. If a batch includes more than one change set, the first change set will be processed by the service, and additional change sets will be rejected with status code 400 (Bad Request).
Important |
|---|
| Multiple operations against a single entity are not permitted within a change set. |
- A batch may include a single query operation that retrieves a single entity. This approach may be used to retrieve an entity when the size of the table name, partition key, and row key exceeds 260 characters and the entity can therefore not be retrieved via a GET operation, due to the HTTP/1.1 limitations on the size of the path part of the URI.
Note that a query operation is not permitted within a batch that contains insert, update, or delete operations; it must be submitted singly in the batch.
- Operations within a change set are processed atomically; that is, all operations in the change set either succeed or fail. Operations are processed in the order they are specified in the change set.
- The Table service does not support linking operations in a change set.
- The Table service supports a maximum of 100 operations in a change set.
Entity Group Transactions via REST
The following sections describe how to construct a batch request and how to interpret the batch response, and show samples of each.
Batch Request Syntax
To perform a batch request via REST, specify the $batch option on the request URI. For example:
http://myaccount.table.core.windows.net/$batch
Note that the request URI does not include the table name.
A batch request is sent to the server with a single POST directive. This request must include the x-ms-version header; the header's value must be set to 2009-04-14.
The XML payload is a multi-part MIME message containing the batch and the change set. The payload includes two MIME boundaries:
- A batch boundary encompasses the change set.
- A change set boundary separates individual insert, update, and delete operations in the batch.
An individual request within the change set is identical to a request made when that operation is being called by itself.
To specify the If-Match header on an update, merge, or delete operation, include the header in the set of request headers for the appropriate operation in the change set.
For detailed information about constructing the batch request, including the request headers, the batch boundary, and the change set boundary, see the .NET Client Library for ADO.NET Data Services.
Sample Request for Insert, Update, and Delete Operations
The following example shows a batch request containing two Insert Entity operations, a Merge Entity operation, and a Delete Entity operation.
POST /$batch HTTP/1.1
User-Agent: Microsoft ADO.NET Data Services
x-ms-version: 2009-04-14
x-ms-date: Thu, 30 Apr 2009 20:45:13 GMT
Authorization: SharedKeyLite myaccount:asOEzsCDS7YEe6oi+bx47KMwbXL0lYZCOlR/oc3FReQ=
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 1.0;NetFx
Content-Type: multipart/mixed; boundary=batch_a1e9d677-b28b-435e-a89e-87e6a768a431
Host: MyHostName:10002
Content-Length: ###
--batch_a1e9d677-b28b-435e-a89e-87e6a768a431
Content-Type: multipart/mixed; boundary=changeset_8a28b620-b4bb-458c-a177-0959fb14c977
--changeset_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
POST http://myaccount.tables.core.windows.net/Blogs HTTP/1.1
Content-ID: 1
Content-Type: application/atom+xml;type=entry
Content-Length: ###
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title />
<updated>2009-04-30T20:45:13.7155321Z</updated>
<author>
<name />
</author>
<id />
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>1</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
<d:Rating m:type="Edm.Int32">9</d:Rating>
<d:Text>.NET...</d:Title>
</m:properties>
</content>
</entry>
--changeset_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
POST http://myaccount.tables.core.windows.net/Blogs HTTP/1.1
Content-ID: 2
Content-Type: application/atom+xml;type=entry
Content-Length: ###
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title />
<updated>2009-04-30T20:45:13.7155321Z</updated>
<author>
<name />
</author>
<id />
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>2</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
<d:Rating m:type="Edm.Int32">9</d:Rating>
<d:Text>Azure...</d:Title>
</m:properties>
</content>
</entry>
--changeset_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
MERGE http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19', RowKey='3') HTTP/1.1
Content-ID: 3
Content-Type: application/atom+xml;type=entry
Content-Length: ###
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title />
<updated>2009-04-30T20:44:09.8869156Z</updated>
<author>
<name />
</author>
<id>http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='3)</id>
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>3</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
<d:Rating m:type="Edm.Int32">9</d:Rating>
<d:Text>PDC 2008...</d:Title>
</m:properties>
</content>
</entry>
--changeset_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
DELETE http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19', RowKey='4') Content-ID: 4
Content-Type: application/atom+xml;type=entry
Content-Length: ###
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title />
<updated>2009-04-30T20:44:09.8869156Z</updated>
<author>
<name />
</author>
<id>http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='3)</id>
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>3</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
<d:Rating m:type="Edm.Int32">9</d:Rating>
<d:Text>PDC 2008...</d:Title>
</m:properties>
</content>
</entry>
--changeset_8a28b620-b4bb-458c-a177-0959fb14c977--
--batch_a1e9d677-b28b-435e-a89e-87e6a768a431--
Sample Request for Queries
The following example shows a batch request for a query. Note that only a single query may be included in the change set.
POST /$batch HTTP/1.1
User-Agent: Microsoft ADO.NET Data Services
x-ms-version: 2009-04-14
x-ms-date: Thu, 30 Apr 2009 20:45:13 GMT
Authorization: SharedKeyLite myaccount:asOEzsCDS7YEe6oi+bx47KMwbXL0lYZCOlR/oc3FReQ=
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 1.0;NetFx
Content-Type: multipart/mixed; boundary=batch_f351702c-c8c8-48c6-af2c-91b809c651ce
Content-Length: ###
--batch_f351702c-c8c8-48c6-af2c-91b809c651ce
Content-Type: application/http
Content-Transfer-Encoding: binary
GET http:// myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='2') HTTP/1.1
--batch_f351702c-c8c8-48c6-af2c-91b809c651ce--
Batch Response Syntax
The response returns an overall status code for the batch request, and individual status codes and result fragments for each operation in the change set. The response is a multi-part MIME message that includes a batch boundary and a change set boundary.
The Table service returns a status code for the entire batch request, and one or more status codes for the operations in the change set, depending on whether they succeeded or failed.
Assuming that the batch request has been properly authenticated and has been successfully received by the Table service, the batch request returns status code 202 (Accepted), even if one of the operations in the change set fails. If the batch request itself fails, it fails before any operation in the change set is executed. For example, the batch request may fail due to an authentication error, in which case the status code will indicate that failure.
Note |
|---|
| If you are using the .NET Client Library to process a batch request that fails prior to executing the operations in the change set, note that the .NET Client Library returns a WebException for this kind of failure, rather than a DataServiceRequestException. |
The operations in a change set are processed atomically; that is, either all operations in the batch succeed, or the entire batch fails. The Table service continues processing operations in the change set until one fails. If an operation fails, all preceding operations in the batch are rolled back. Additionally, entity group transactions execute with snapshot isolation.
The status code for an individual operation within a change set appears within the change set response. When an individual operation fails, the response for the change set indicates status code 400 (Bad Request). Additional error information within the response indicates which operation failed by returning the index of that operation. The index is the sequence number of the command in the payload.
Note |
|---|
| The Table service does not guarantee the order in which operations are executed. |
For an example, see the sample error response below.
Sample Response for Create, Update, and Delete Operations
The following example shows the response for the batch operations sent in the sample request shown above.
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: multipart/mixed; boundary=batchresponse_dc0fea8c-ed83-4aa8-ac9b-bf56a2d46dfb
Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: b4b49b3e-19a9-4091-a280-da76a09da8d4
Date: Thu, 30 Apr 2009 20:44:09 GMT
334
batchresponse_dc0fea8c-ed83-4aa8-ac9b-bf56a2d46dfb
Content-Type: multipart/mixed; boundary=--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977
--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Content-ID: 1
Content-Type: application/atom+xml;charset=utf-8
Cache-Control: no-cache
ETag: W/"datetime'2009-04-30T20%3A44%3A09.5789464Z'"
Location: http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='1')
DataServiceVersion: 1.0;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http:// myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/"datetime'2009-04-30T20%3A44%3A09.5789464Z'"" xmlns="http://www.w3.org/2005/Atom">
<id> http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='1')</id>
<title type="text"></title>
<updated>2009-04-30T20:44:09Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Blogs" href=" Blogs(PartitionKey='Channel_19',RowKey='1')" />
<category term="myaccount.Blogs" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>1</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">2009-04-30T20:44:09.5789464Z</d:Timestamp>
<d:Text>.Net...</d:RowKey>
<d:Rating m:type="Edm.Int32">9</d:Rating>
</m:properties>
</content>
</entry>
--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Content-ID: 2
Content-Type: application/atom+xml;charset=utf-8
Cache-Control: no-cache
ETag: W/"datetime'2009-04-30T20%3A44%3A09.5789464Z'"
Location: http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='2')
DataServiceVersion: 1.0;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http:// myaccount.tables.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/"datetime'2009-04-30T20%3A44%3A09.5789464Z'"" xmlns="http://www.w3.org/2005/Atom">
<id> http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='2')</id>
<title type="text"></title>
<updated>2009-04-30T20:44:09Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Blogs" href=" Blogs(PartitionKey='Channel_19',RowKey='2')" />
<category term="myaccount.Blogs" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>2</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">2009-04-30T20:44:09.5789464Z</d:Timestamp>
<d:Text>Azure...</d:RowKey>
<d:Rating m:type="Edm.Int32">9</d:Rating>
</m:properties>
</content>
</entry>
--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 204 No Content
Content-ID: 3
Cache-Control: no-cache
ETag: W/"datetime'2009-04-30T20%3A44%3A10.0019041Z'"
DataServiceVersion: 1.0;
--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 204 No Content
Content-ID: 4
Cache-Control: no-cache
DataServiceVersion: 1.0;
--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977--
--batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83--
0
Sample Response for Queries
The following example shows the response for the query sent in the sample request shown above.
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: multipart/mixed; boundary=batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83
Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 9202c4a1-43af-4dc0-baca-aa71f7a7407b
Date: Thu, 30 Apr 2009 20:44:10 GMT
1DC1
--batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/atom+xml;charset=utf-8
Cache-Control: no-cache
ETag: W/"datetime'2009-04-30T20%3A44%3A10.0019041Z'"
DataServiceVersion: 1.0;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://127.0.0.1:10002/testaccount1/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/"datetime'2009-04-30T20%3A44%3A10.0019041Z'"" xmlns="http://www.w3.org/2005/Atom">
<id> http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='1')</id>
<title type="text"></title>
<updated>2009-04-30T20:44:10Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Blogs" href=" Blogs(PartitionKey='Channel_19',RowKey='2')" />
<category term="myaccount.Blogs" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>2</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">2009-04-30T20:44:09.5789464Z</d:Timestamp>
<d:Text>.Net...</d:RowKey>
<d:Rating m:type="Edm.Int32">9</d:Rating>
</m:properties>
</content>
</entry>
--batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83--
0
Sample Response for Queries
The following example shows the response for the query sent in the sample request shown above.
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: multipart/mixed; boundary=batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83
Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 9202c4a1-43af-4dc0-baca-aa71f7a7407b
Date: Thu, 30 Apr 2009 20:44:10 GMT
1DC1
--batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/atom+xml;charset=utf-8
Cache-Control: no-cache
ETag: W/"datetime'2009-04-30T20%3A44%3A10.0019041Z'"
DataServiceVersion: 1.0;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://127.0.0.1:10002/testaccount1/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/"datetime'2009-04-30T20%3A44%3A10.0019041Z'"" xmlns="http://www.w3.org/2005/Atom">
<id> http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='1')</id>
<title type="text"></title>
<updated>2009-04-30T20:44:10Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Blogs" href=" Blogs(PartitionKey='Channel_19',RowKey='2')" />
<category term="myaccount.Blogs" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:PartitionKey>Channel_19</d:PartitionKey>
<d:RowKey>2</d:RowKey>
<d:Timestamp m:type="Edm.DateTime">2009-04-30T20:44:09.5789464Z</d:Timestamp>
<d:Text>.Net...</d:RowKey>
<d:Rating m:type="Edm.Int32">9</d:Rating>
</m:properties>
</content>
</entry>
--batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83--
0
Sample Error Response
The following example shows a response from a batch request containing an operation that failed. Note that the batch response returns status code 202 (Accepted), but the individual operation that failed returns status code 400 (Bad Request). The additional error information is included in the response body for the failed operation. The code element specifies the storage service error code, whereas the message element begins with the index of the failed operation, followed by the error message string. To determine which operation failed, parse the index value from the message. Operations are indexed beginning at zero.
In this example, note that the operation that failed was the fourth operation in the change set. Within the message element, the message begins with the numeral 3, followed by the extended error information.
<message xml:lang="en-US">3:One of the request inputs is not valid.</message>
Here is the complete response:
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: multipart/mixed; boundary=batchresponse_7ab1553a-7dd6-44e7-8107-bf1ea1ab1876
Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 45ac953e-a4a5-42ba-9b4d-97bf74a8a32e
Date: Thu, 30 Apr 2009 20:45:13 GMT
6E7
--batchresponse_7ab1553a-7dd6-44e7-8107-bf1ea1ab1876
Content-Type: multipart/mixed; boundary=changesetresponse_6cc856b4-8cb9-41eb-b8d2-bb73475c6cec
--changesetresponse_6cc856b4-8cb9-41eb-b8d2-bb73475c6cec
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 400 Bad Request
Content-ID: 4
Content-Type: application/xml
Cache-Control: no-cache
DataServiceVersion: 1.0;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>InvalidInput</code>
<message xml:lang="en-US">3:One of the request inputs is not valid.</message>
</error>
--changesetresponse_6cc856b4-8cb9-41eb-b8d2-bb73475c6cec--
--batchresponse_7ab1553a-7dd6-44e7-8107-bf1ea1ab1876--
0
Entity Group Transactions via the .NET Client Library
The Table service supports using the .NET Client Library for ADO.NET Data Services to perform entity group transactions. To submit a changeset containing insert, update, and delete operations, call the SaveChanges method of the DataServicesContext object, with the SaveChangesOptions.Batch option. You can also call the BeginSaveChanges and EndSaveChanges methods to save changes asynchronously.
You can execute a single query within a single batch by calling the ExecuteBatch method. To execute a single query asynchronously, call BeginExecuteBatch and EndExecuteBatch. Note that calling these methods with a batch containing more than one query is not currently supported.
The following code excerpt demonstrates using the SaveChanges method to insert a set of entities:
for (int index = 0; index < 20; index++)
{
Blog blog = new Blog(
userId /* partition key */,
string.Format("{0:D19}", i) /* row key - blog id*/,
DateTime.UtcNow /* blog creation date */,
title,
message);
context.AddObject(blog);
}
// All operations above are executed as a single batch request.
DataServiceResponse response = context.SaveChanges(SaveChangesOptions.Batch);
See Also