0% found this document useful (0 votes)
270 views53 pages

Microsoft Azure Development Cookbook Second Edition Sample Chapter

Chapter No. 5 Going NoSQL with Azure Tables Over 70 advanced recipes for developing scalable services with the Microsoft Azure platform

Uploaded by

Packt Publishing
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
270 views53 pages

Microsoft Azure Development Cookbook Second Edition Sample Chapter

Chapter No. 5 Going NoSQL with Azure Tables Over 70 advanced recipes for developing scalable services with the Microsoft Azure platform

Uploaded by

Packt Publishing
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 53

Microsoft Azure

Development Cookbook
Second Edition







Roberto Freato
Neil Mackenzie








Chapter No 5
"Going NoSQL with Azure Tables"
In this package, you will find:
The authors biography
A preview chapter from the book, Chapter no.5 "Going NoSQL with Azure Tables"
A synopsis of the books content
Information on where to buy this book








About the Authors
Roberto Freato has been an independent IT consultant since he started working. He
worked for several small software firms while he was studying. After completing his
MSc in Computer Science and Engineering, where he worked on a thesis on Consumer
Cloud Computing, he specialized in cloud and Azure. Today, he works as a freelance
consultant for important companies in Italy, helping clients design and kick-off their
distributed software solutions. He trains for the developer community in his free time,
addressing many conferences. He is a Microsoft MVP since 2010.
Thanks to Simona, Mom, and Dad.

Neil Mackenzie has worked with computers for nearly 3 decades. He started his
computer career doing large-scale numerical simulations for scientific research and
business planning. Since then, he has primarily been involved in healthcare software
and developing electronic medical record systems. He has been using Microsoft Azure
since PDC 2008 and has used nearly all parts of the Microsoft Azure platform,
including those parts that no longer exist. Neil is very active in the online Microsoft
Azure community, contributing to the MSDN Microsoft Azure forums in particular.
He is a Microsoft MVP for Microsoft Azure.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book


I would like to thank all the people from whom I've learned Microsoft
Azure. I would also like to thank the staff at Packt Publishing for
nursing the project along and Brent Stineman for first suggesting my
name to them. I have found the comments from the technical
reviewers invaluable, which immeasurably improved the book. Last
but not least, I would like to thank my wife, Claire, and my children
for suffering through all the late nights and lost weekends that went
into the writing of the book.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Microsoft Azure
Development Cookbook
Second Edition
Microsoft Azure is Microsoft's platform for cloud computing. It provides developers with
elastic building blocks to build scalable applications. These building blocks are services
for web hosting, storage, computation, connectivity, and more. They are usable as
standalone services or are mixed together to build advanced scenarios.
This practical cookbook will show you these building blocks, focusing on why we should
use one or the other, and when to use them appropriately. Even though reading the entire
book will give you an advanced overview of the main blocks of the Azure platform, each
chapter is self-contained. So, even an inexperienced reader could jump from one chapter
to another without reading the entire book. Each chapter is organized into recipes
standalone units of execution to complete tasks that involve a specific feature/service of
the platform. This approach gives readers the capability to focus on the technology for
further use in real-world projects.
This book tries to provide a comprehensive overview of the main aspects of the Azure
platform from the point of view of a developer. Some building blocks such as virtual
machines are deliberately avoided to focus on development tools, development libraries,
and development strategies. This is a recipe-based book; expect to dirty your hands
with code that is also outside the boundaries of the recipe, as you would do with food in
a real recipe.
Finally, Microsoft Azure is an evolving platform. As technical topics have a high decay
rate, Azure services are enriched day by day with new features and service models,
making the goal of writing a "complete" book almost impossible. However, this book
focuses on core concepts, which remain quite stable over time.
What This Book Covers
Chapter 1, Developing Cloud Services for Microsoft Azure, shows you the main compute
engine of Azure (also known as web/worker roles). This building block uses a specific
service model to run web applications as well as any other custom code on stateless
virtual machines. This chapter is also a great introduction to Visual Studio integration for
those who are not familiar with it.
Chapter 2, Deploying Quickly with Azure Websites, shows you one of the most advanced
Platform as a Service in the market, which lets customers/developers deploy an existing
web application in minutes. This building block does not require a specific development
skill, as it is a lock-in-free environment that provides advanced integrated features


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book


regarding the ALM. This chapter is essential for anyone who wants to start a new project
or move an existing project to the cloud.
Chapter 3, Getting Storage with Blobs in Azure, shows you how Azure deals with storage
of files (also known as Blobs). This building block is about Blobs' features, management,
and administration, with food for thought for advanced scenarios. This chapter will be
helpful to those who want to access the storage services programmatically.
Chapter 4, Going Relational with the Azure SQL Database, shows you the RDBMS of
Microsoft Azure, enabling existing SQL-Server-based solutions to move into the cloud
seamlessly. This building block is about SQL database management, monitoring, and
development. This chapter is a good read to identify the correct approach to SQL on
Microsoft Cloud.
Chapter 5, Going NoSQL with Azure Tables, shows you how to use the original Table
service as a data store for unstructured data. This building block can be used to store
entities when there is no strict need of a SQL-based, but scalable, service. This chapter
is particularly useful while building a scalable data store of arbitrary entities.
Chapter 6, Messaging and Queues with Storage and Service Bus, shows you how to
build scalable systems with message-based, disconnected systems. This building block
covers the need for communication between heterogeneous systems, using queues of
messages. This chapter also covers the relayed messaging feature and cross-platform
communication.
Chapter 7, Managing Azure Resources with the Azure Management Libraries, shows you
how to remotely manage a big portion of the Azure services, programmatically, through
Management Libraries. The building block is the Management API on which
Management Libraries rely. This chapter is suited for automation solutions, custom
management tools, or even parts of complex multitenant systems where resources must
be created/configured/ destroyed dynamically.
Chapter 8, Going In-memory with Azure Cache, shows you how to improve an
application's performance with in-memory caching. This building block is of primary
importance for situations where there's web traffic and the demand is high, providing
good service by storing frequently accessed information. This chapter is about
caching, so it is extremely important to read it even if you are not adopting it as part
of the implementation.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

5
Going NoSQL with
Azure Tables
In this chapter, we will cover the following topics:
Creating a table
Inserting, updating, deleting, and querying data against the Table service
Using entity group transactions
Using continuation tokens and server-side paging
Going inside continuation tokens and segmented queries
Handling entity serialization events
Facilitating NoSQL with client-side projection
Introduction
The Microsoft Azure Table Service is the Storage service feature that provides cost-effective
scalable storage of entities.
During the last 3 decades, relational databases have become the dominant data storage
systems. Relational databases are transaction oriented and implement ACID semantics
in which database transactions are atomic, consistent, isolated, and durable. These are
important considerations for a data system where data delity is of absolute importance,
such as those used in a nancial system. However, large-scale data systems that implement
ACID semantics are extremely expensive, as they require huge infrastructures behind them.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
226
In the last decade, there has been a growing interest in creating cost-effective, large-scale
data systems. This interest is driven primarily by those in need of data collection, such as the
data-mining needs of social websites that generate enormous amounts of click-stream data
or scientic datasets. Much of this data is read only, so there is less emphasis on support for
transactions. Furthermore, these data systems typically do not provide support for SQL, so
they are referred to as NoSQL systems with No being an acronym for not only.
Some NoSQL data systems implement BASE semantics that are basically available in the soft
state; they are eventually consistent rather than ACID semantics. The idea is that a change to
stored data does not have to be immediately consistent across the data system as long as it is
eventually consistent.
The Table service is the NoSQL data system provided by the Azure Platform. It provides
large-scale storage at a cost signicantly lower than that provided by the Azure SQL Database,
the relational database provided in the Azure Platform.
The Table service uses storage accounts to provide an authentication boundary. Unlike a
relational database, these tables have no xed schema, and each entity stored in the table
denes its own schema. We see how to create a table in the Creating a table recipe.
An entity is a collection of properties and their associated values. The primary key for a table
is the combination of two properties, PartitionKey and RowKey, that must be present in
each entity stored in the table. The Table service uses PartitionKey to provide scalability
(partitioning data) and RowKey to ensure uniqueness within a given partition. The entities
in a table with the same PartitionKey property comprise a partition.
The Azure Storage Service REST API provides the denitive interface to the Table service. The
Azure Storage library is a high-level, managed .NET API for the Table service that hides the
underlying Storage Service REST interface. The Storage Client library, at the time of writing
this book, supports two methods to operate against the Table service: a former one and a
newer one. The former extends the WCF Data Services stack, while the latter introduces a
new Table service layer (also based on OData) with major performance optimization and new
features. It is likely that the former method will be eventually deprecated, but as it is used by
many existing applications and is still effective, we decided to implement both in this book.
In the recipes of this chapter, we will see how to achieve results in
both the patterns/methods mentioned earlier; we call these patterns/
methods Method1 (the WCF Data Service pattern) and Method2
(the new Table service layer).
The Storage library provides developers with a functionality specic to the Table service, such
as authentication, server-side paging, and automated retry logic. All the recipes in this chapter
use the Storage library.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
227
In the WCF Data Services paradigm, we associate table entities with a model class. To some
extent, this imposes a schema on the table, although many model classes could be associated
with a single table. It uses a context to track instances of the model class; these instances
represent the entities to be inserted in the table or retrieved from the table. We will go further
into this in the Inserting, updating, deleting, and querying data against the Table service recipe.
The Table service provides limited support for ACID semantics. Up to 100 storage operations
against the same partition might be batched into a single entity group transaction and
performed as a single transaction in which either all operations succeed or all operations
are rejected (with a maximum total payload size of 4 MB). We will consider these in the
Using entity group transactions recipe. Note that the Table service does not implement BASE
semantics, as it uses hard state, with all data changes being strongly consistent.
Optimistic concurrency is a technique used in NoSQL data systems to avoid the scalability
problems caused by data being locked to prevent simultaneous updates by different clients.
The Table service implements optimistic concurrency by providing an entity tag (ETag) with
each entity it returns to a client. A subsequent update succeeds only if the current ETag tag
is provided. This provides a lightweight and scalable way to manage concurrent updates to an
entity. We will look at optimistic concurrency in the Using entity group transactions recipe.
The Table service supports the concept of server-side paging in which no more than 1,000
entities are returned in response to a query, in no more than 5 seconds. When this throttling
occurs, the Table service also returns continuation tokens that the client can use to reissue
the query for the next page of data. We will show this in the Using continuation tokens and
server-side paging and Going inside continuation tokens and segmented queries recipes.
The Azure Storage library takes care of the serialization/deserialization of entities against
the REST API, but we can customize this behavior, thanks to some extension endpoints in
the library. In the Handling entity serialization events recipe, we will see how to control the
serialization process.
NoSQL data stores are generally classied by how they organize their aggregates, the single
and minimal unit of storage. In RDBMS, we can say that the row is the minimal unit of storage,
while in NoSQL, it can vary. The Azure Table service organizes its data in entities; an entity is
dened by the PartitionKey and RowKey properties, but it can contain several key-value
pairs. We can also say that an entity is a key-value pair collection. Under these circumstances,
it could not be easy to dene a single entity model (in a programming language) that could
map the result of a given query against the service. Instead, a more generic result for a given
entity should be a collection of key-value pairs. In the Facilitating NoSQL with client-side
projection recipe, we will see how to deal with this.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
228
Creating a table
The Azure Table service supports a simple two-level hierarchy. There is a single level
of tables, each of which contains zero or more entities. An entity can have up to 255
properties, including three system-dened properties, and there is no requirement that
different entities in the same table have the same properties. This feature makes the Table
service schemaless. The only requirement of entities in a table is that the combination of
PartitionKey and RowKey properties is distinct for each entity in a table. Consequently,
when a table is created, the only required information is its name.
The Azure Storage library contains a CloudTableClient class that provides a set of
synchronous and asynchronous methods that support the creation and deletion of tables.
It also supports the listing of the tables associated within an Azure Storage service's
storage account.
In this recipe, we will learn how to use the synchronous methods to create and delete tables
as well as list them.
Getting ready
This recipe assumes that the following lines of code are in the application's conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with appropriate values for the
account name and access key, respectively.
How to do it...
We are going to create two tables, list the tables, and then delete a table. We will do this using
the following steps:
1. Add a new class named TablesExample to the project.
2. Install the WindowsAzure.Storage NuGet package and add the following
assembly references to the project:
System.Configuration


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
229
3. Add the following using statements to the top of the class le:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using System.Configuration;
4. Add the following member to the class:
private CloudTableClient cloudTableClient;
5. Add the following constructor to the class:
TablesExample()
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
}
6. Add the following method, creating a table, to the class:
public void CreateTable(String tableName,
Boolean checkExistence = false)
{
CloudTable table=cloudTableClient
.GetTableReference(tableName);
if (checkExistence)
{
table.CreateIfNotExists();
}
else
{
table.Create();
}
}
7. Add the following method, deleting a table, to the class:
public bool DeleteTable(String tableName)
{
CloudTable table = cloudTableClient
.GetTableReference(tableName);
table.DeleteIfExists();
return !table.Exists();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
230
8. Add the following method, listing the tables, to the class:
protected void ListTables(String tableNamePrefix)
{
IEnumerable<CloudTable> listTablesPrefix =
cloudTableClient.ListTables(tableNamePrefix);
Int32 countListTablesPrefix =
listTablesPrefix.Count();
IEnumerable<CloudTable> listTables =
cloudTableClient.ListTables();
Int32 countListTables = listTables.Count();
}
9. Add the following method to the class:
public static void UseTablesExample()
{
TablesExample example = new TablesExample();
example.CreateTable("Stars");
example.CreateTable("Planets", true);
example.ListTables("P");
example.DeleteTable("Planets");
}
How it works...
In steps 1 through 3, we set up the class. In step 4, we added a private member to store
the CloudTableClient instance used to connect to the Table service. We initialized this
in the constructor we added in step 5.
In step 6, we added a method that shows two ways to create a table, starting from an instance
of CloudTable. The rst invoked CreateIfNotExists(), which created the table only if it
did not already exist. The second invoked Create(), which throws an exception if the table
already existed (HTTP error code 409, which means Conict). In step 7, we added a method
that deleted a table. This method is safe due to the DeleteIfExists() method.
In step 8, we added a method to list all the tables in the storage account. It did so in two
different ways: with and without using a prex. In step 9, we added a simple method to use
the methods we added earlier. We created a couple of tables, listed all the tables in the
storage account, and then deleted one of the tables.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
231
There's more
The Azure Table service is cloud based. In the Azure SDK, Microsoft provides a Storage
Emulator, which runs in the development environment and can be used for local development
and testing. This emulator uses LocalDB, but it can also be congured to the use Microsoft
SQL Server.
There are some circumstances in which the Storage Emulator and the Table service behave
differently. Consequently, when problems are identied while developing with the Storage
Emulator, it is often useful to check whether the problem exists when using the Table service.
The Azure Storage Service REST API is the denitive way to interact with the Table service.
The Azure Storage library is a high-level .NET library that sits on top of the Storage Service
REST API.
A utility such as Fiddler, which allows us to inspect HTTP trafc, can be helpful in identifying
problems when developing against either the Table service or the Storage Emulator. Fiddler
makes it easy to verify that the correct REST operations are invoked and to check the request,
response headers, and payloads. These can be compared with the MSDN documentation in
the Azure Storage Service REST API. Fiddler also provides direct access to any error message
returned by the Storage Service REST API.
No special conguration is required to use Fiddler with the Table service. Fiddler merely needs
to be running to capture all the network trafc to and from the Azure Table service. However, a
special connection string must be provided when using Fiddler with the Storage Emulator. In
this case, the data connection string must be set to the following:
UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://ipv4.
fiddler
Although Fiddler is useful in identifying problems, it can introduce problems when used
with the Storage Emulator, while it always behaves correctly when used with the real
cloud environment.
See also
Have a look at these MSDN links to get additional information:
Differences between the Storage Emulator and Azure Storage at http://msdn.
microsoft.com/en-us/library/azure/gg433135.aspx
Using the Table storage from Node.js at http://azure.microsoft.com/en-us/
documentation/articles/storage-nodejs-how-to-use-table-storage/


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
232
Inserting, updating, deleting, and querying
data against the Table service
The Azure Storage library uses both WCF Data Services and OData to invoke table operations
in the Azure Storage Services REST API. The library has methods that provide functionality
specic to the Azure Table service, such as the retry functionality that allows methods to be
retried automatically in the event of failure and continuation token functionality that supports
server-side paging.
In the Storage library, instances of a model class represent entities of a table. When saving
an instance to a table, the Storage library creates a property in the entity for each public
property of the instance. The model class must contain the primary key properties for the
entity: PartitionKey and RowKey. An entity can have no more than 252 user-dened
properties (due to the primary key properties plus the Timestamp properties). Furthermore,
if it is used to store query results, the model class must have a default constructor that takes
no parameters. The Storage library provides a convenient base class from which to derive
model classes for both Method1 and Method2. They are the TableServiceEntity and the
TableEntity classes, respectively.
The Storage Client library supports only the following datatypes for entities:
Byte[]
Boolean
DateTime
Double
Guid
Int32
Int64
String
Both Byte[] and String are limited to no more than 64 KB. Note that the Storage Client
library automatically converts DateTime values to the local time zone when retrieving
entities. Each entity has a maximum size of 1 MB.
Method1 uses DataServiceContext to expose storage operations and queries, as well as
to track entities used in these storage operations and queries. Entities are tracked by adding
them as new entities using DataServiceContext.AddObject() or attaching them to
the context with the DataServiceContext.AttachTo() method that provides additional
functionality to update entities. Entities returned by queries are also tracked. Any changes to
tracked entities are submitted as individual storage operations when the SaveChanges()
method is invoked on the context.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
233
The Storage library contains a TableServiceContext class, derived from
DataServiceContext, which adds the retry functionality to the synchronous
and asynchronous SaveChanges() methods through the provision of the
SaveChangesWithRetries() methods. It can be convenient to create a model-dependent
class derived from TableServiceContext. This can be generalized by creating a generic
class parameterized by the type of the model class. Doing so simplies the text of queries
and provides type-safe methods to manage entities.
The following two code fragments demonstrate this simplication:
from c in tableServiceContext.CreateQuery<Country>("Country")
from c in countryContext.GenericEntities
The rst example explicitly uses TableServiceContext to create a query, while the second
uses a generic context class that exposes a GenericEntities property, which encapsulates
the CreateQuery<Country>() method.
Contexts should not be reused, that is, unrelated storage operations should use
different contexts.
When we have asynchronous operations being performed against the
Table Storage service, the operations might take longer than expected and
leave the context in an unpredictable state. Hence, it is recommended that
the context be recreated even to retry the same operation, to isolate the
retry attempts completely.
Method2 uses a CloudTable reference to execute commands against the Table service,
with the Execute and ExecuteQuery methods. The rst method takes an instance of
TableOperation as a parameter; it identies a CRUD action against the datastore. The
second one takes a TableQuery instance that can be constructed by string-based queries
as follows:
new TableQuery().Where("PartitionKey eq 'Italy'")
To help developers while writing this challenging syntax, TableQuery provides a static
method to generate the necessary strings for the query operators needed by the Where
clause. To further help developers who work on a familiar set of classes and with LINQ, there
is also a LINQ provider to query data against a table, using the CreateQuery<T> method on
the CloudTable instance.
In this recipe, we'll learn how to create a model class and use the two methods to perform
various storage operations and queries.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
234
Getting ready
This recipe assumes that the following lines of code are in the application's conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with the appropriate values
for the account name and access key, respectively.
How to do it...
We are going to perform an insert, update, and delete operation on the Table service
for a query to retrieve data. We will do this using the following steps:
1. Add a new class named ModelContextExample to the project.
2. Install the WindowsAzure.Storage NuGet package and add the following
assembly references to the project:
System.Configuration
3. Add the following using statements to the top of the class le:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System.Configuration;
4. Add the following member to the class:
private CloudTableClient cloudTableClient;
5. Add the following constructor to the class:
private ModelContextExample(String tableName)
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
var table=cloudTableClient.GetTableReference(tableName);
table.CreateIfNotExists();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
235
Now, let's proceed with Method1.
6. Add the following class in the project:
public class CountryDS : TableServiceEntity
{
private readonly String partitionKey = "country";
public String CapitalCity { get; set; }
public Int64 Population { get; set; }
public CountryDS() { }
public CountryDS(String name, String capitalCity,
Int64 population)
{
PartitionKey = partitionKey;
RowKey = name;
CapitalCity = capitalCity;
Population = population;
}
}
7. Add the following method to the ModelContextExample class:
private void InsertQueryAndUpdateMethod1()
{
TableServiceContext tableServiceContext =
cloudTableClient.GetTableServiceContext();
tableServiceContext.AddObject("Country",
new CountryDS("Australia", "Canberra", 22558947));
tableServiceContext.AddObject("Country",
new CountryDS("India", "New Delhi", 1189914000));
tableServiceContext.SaveChangesWithRetries();
var query = tableServiceContext.CreateQuery<CountryDS>("Count
ry")
.Where(p => p.PartitionKey == "country" && p.RowKey ==
"Australia");
CountryDS country = query.FirstOrDefault<CountryDS>();
country.Population += 100000;
tableServiceContext.UpdateObject(country);
tableServiceContext.SaveChangesWithRetries();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
236
8. Add the following method to the ModelContextExample class:
private void DeleteAllMethod1()
{
TableServiceContext tableServiceContext =
cloudTableClient.GetTableServiceContext();
var items = tableServiceContext.CreateQuery<CountryDS>("Count
ry");
foreach (var item in items)
{
tableServiceContext.DeleteObject(item);
}
tableServiceContext.SaveChangesWithRetries();
}
Now, let's proceed with Method2.
9. Add the following class to the project:
public class Country : TableEntity
{
private readonly String partitionKey = "country";
public String CapitalCity { get; set; }
public Int64 Population { get; set; }
public Country() { }
public Country(String name, String capitalCity,
Int64 population)
{
PartitionKey = partitionKey;
RowKey = name;
CapitalCity = capitalCity;
Population = population;
}
}
10. Add the following method to the ModelContextExample class:
private void InsertQueryAndUpdateMethod2()
{
var table = cloudTableClient.GetTableReference("Country");

var c1= new Country("Australia", "Canberra", 22558947);


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
237
var c2 = new Country("India", "New Delhi", 1189914000);
var op1=TableOperation.Insert(c1);
var op2=TableOperation.Insert(c2);
table.Execute(op1);
table.Execute(op2);
var query=table.CreateQuery<Country>()
.Where(p => p.PartitionKey == "country" &&
p.RowKey == "Australia");

Country country = query.FirstOrDefault();
country.Population += 100000;
table.Execute(TableOperation.Merge(country));

}
11. Add the following method to the ModelContextExample class:
private void DeleteAllMethod2()
{
var table = cloudTableClient.GetTableReference("Country");
var items = table.CreateQuery<Country>();
foreach (var item in items)
{
table.Execute(TableOperation.Delete(item));
}
}
In both cases, follow this final step.
12. Add the following method to the ModelContextExample class:
public static void UseModelContextExample()
{
String tableName = "Country";
ModelContextExample example =
new ModelContextExample(tableName);
example.InsertQueryAndUpdateMethod1();
example.DeleteAllMethod1();
example.InsertQueryAndUpdateMethod2();
example.DeleteAllMethod2();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
238
How it works...
In steps 1 through 4, we set up the ModelContextExample class, and in step 5, we created
a constructor that initializes the CloudTableClient instance to create a table that was
specied as argument.
We then split the recipe into two branches: the rst for the Method1 and second for
the Method2.
In step 6, we added a model class named CountryDS, which inherits from
TableServiceEntity, to represent entities that describe various properties of countries.
The PartitionKey property is always set to the country for entities created using this class.
The RowKey property is set to the name of the country. The Timestamp property, even if
it is not directly visible (due to its belonging to the base class), is one of the three system
properties present in each entity. In practice, it is not really needed in the model class. There
are two constructors: one being the required parameterless constructor and the other fully
initializing an instance of the model class.
In step 7, we added a method that uses TableServiceContext to add several entities to
the Country table. It then queried the table to retrieve a single entity and updated this entity
to the table. We used the SaveChangesWithRetries() method, which performs automatic
retries, in case of transient failures on the service side.
While writing distributed applications (not only for Azure), a common
approach to follow is to design software that is failure proof or, better,
designed for failures. The Azure Storage service is a great service, but it
can throttle a request or can be temporarily out of service. In some cases,
a denial of service is due to a transient failure, and the corresponding
action to recover it is just the retry.
In step 8, we added a method to delete each object of the Country table. As shown in the
code, it is required to rst fetch the entities and then delete them one by one.
In step 9, since we followed Method2, we created another model class, inheriting now the
TableEntity base class. This new model class is used by the Table service layer to perform
operations against the table, even if it is actually identical to its peer created in step 6.
In step 10, we added a method that uses the Execute method of a CloudTable instance to
add several entities to the Country table. Since the Execute method is operation aware, we
needed to build the operation in advance with the helpers provided by the static methods of
the TableOperation class. It then queried the table to retrieve a single entity and updated
that entity to the table, using the same pattern by invoking the Execute method.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
239
In step 11, we added a method to delete each object of the Country table. As shown in the
code, it is still required to rst fetch the entities and then delete them one by one. However,
it is possible to optimize this behavior using the DynamicTableEntity pattern, as shown
in the Facilitating NoSQL with client-side projection recipe.
In step 12, we added a method that uses the methods we added in the previous steps.
There's more
Now, we see how to work with a custom context and how to choose partition and row
keys appropriately.
Dealing with a custom context
With Method1, instead of using the TableServiceContext class to operate against the
Table service, we can also create our custom context to wrap the strongly typed entities
to simplify the further query needs (or to use the Repository pattern instead of using
context methods) as follows:
1. Add the following class to the project:
public class CustomContext<T> : TableServiceContext
{
public String TableName { get; set; }
public CustomContext(
CloudTableClient client)
: base(client)
{
Type type = typeof(T);
TableName = type.Name;
}
public void AddEntity(T entity)
{
AddObject(TableName, entity);
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
240
public void DeleteEntity(T entity)
{
DeleteObject(entity);
}
public IQueryable<T> GenericEntities
{
get { return CreateQuery<T>(TableName); }
}
}
2. Add the following method to the ModelContextExample class:
private void InsertQueryAndUpdateMethod1bis()
{
CustomContext<Country> countryContext =
new CustomContext<Country>(cloudTableClient);
countryContext.AddEntity(
new Country("France", "Paris", 63900000));
countryContext.AddEntity(
new Country("Italy", "Rome", 59600000));
countryContext.SaveChangesWithRetries();
var query = countryContext.GenericEntities
.Where(p => p.PartitionKey == "country"
&& p.RowKey == "France");
Country country = query.FirstOrDefault();
country.Population += 100000;
countryContext.UpdateObject(country);
countryContext.SaveChangesWithRetries();
}
In step 1, we added a generic-context class, GenericContext<T>, derived from
TableServiceContext. We inferred the table name from the name of the type. The
constructor for this class simply invoked the base class constructor. We added a type-safe
method to add objects to the context. Finally, we added a GenericEntities property that
returned an IQueryable<T> class, which we used to simplify the syntax for queries.
In step 2, we added a method that used GenericContext<Country> to add several
entities to the Country table. It then queried the table to retrieve a single entity and
updated this entity in the table.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
241
Choosing a good combination of PartitionKey and RowKey
The primary key for a table in the Azure Table service is the combination of PartitionKey
and RowKey. These properties are not symmetric, in that PartitionKey and RowKey serve
different purposes. The PartitionKey property provides scalability for a table, while the
RowKey property ensures uniqueness for a given value of PartitionKey.
A set of entities with the same PartitionKey property in a table is referred to as a partition.
The Table service has a scalability target for a partition that is lower than that for the
storage account. Consequently, performance can be improved by ensuring that data access
is distributed across partitions. It is important for PartitionKey to be designed so that
performance is optimized for the actual workload of a service while minimizing unnecessary
partitioning or interrelated data.
When a query is executed against a table, the resulting entities are ordered by
PartitionKey and then by RowKey. The Table service does not support any other index.
Consequently, if entities must be retrieved in a particular order, the RowKey property must be
constructed to facilitate this order. An interesting case is where entities must be retrieved in
reverse chronological order. Each DateTime has an associated Ticks property that species
the number of ticks since the earliest DateTime property. A chronological order for RowKey
can be achieved using the Ticks count for a DateTime property of RowKey. A reverse
chronological ordering can be achieved by subtracting the number of ticks from the Ticks
count for the maximum value of DateTime. For example, the following code calculates the
number of ticks remaining from now until the maximum number of ticks:
DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks
When converted to a string, as required for the RowKey property, this requires 19 characters
to ensure that all the possible values can be represented. The Ticks count can be converted
as follows:
String.Format("{0:D19}",
DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks);
This creates a 19-character string that, when used for the RowKey property, creates a reverse
chronological ordering.
See also
Have a look at the following MSDN links to get additional information:
More about the Table service data model at http://msdn.microsoft.com/en-
us/library/azure/dd179338.aspx
The WCF Data Service documentation center at http://msdn.microsoft.com/
en-us/data/odata.aspx


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
242
Using entity group transactions
The Azure Table service supports entity group transactions in which a group of storage
operations on entities with the same PartitionKey property are handled automatically.
That is, if any operation in the group fails, then all the operations are rolled back. Unlike
transactions in a traditional SQL database, entity group transactions cannot span tables
or even partitions.
A single entity group transaction is limited to no more than 100 entities and a total size
of 4 MB. An individual entity can be used only once in an entity group transaction. Any
combination of the create, update, and delete operations can be contained in an entity
group transaction. Alternatively, it can contain only query operations. However, an entity
group transaction might not combine queries with the create, update, and delete operations.
Handling batch operations differs much between Method1 and Method2. With WCF Data
Services, we control the save operation with the SaveChanges() method. The default
behavior when a SaveChanges() or SaveChangesWithRetries() method is invoked
on a context is that any changes to entities tracked by the context are submitted to the
Table service, one storage operation at a time. Specifying a SaveChangesOptions.Batch
parameter for these methods causes all the changes to be submitted as a single entity
group transaction.
With the new Table service layer, we have a new explicit ExecuteBatch() method on the
CloudTable instance. This method takes a TableBatchOperation class as a parameter;
this class is a sort of container for multiple operations.
Regardless of how many individual storage operations a single entity group transaction
contains, it is billed as a single storage operation. This will considerably save costs over
performing the storage operations individually.
In this recipe, we will learn how to use entity group transactions.
Getting ready
This recipe uses model classes named Country and CountryDS that are declared in the
Inserting, updating, deleting, and querying data against the Table service recipe. This recipe
also assumes that the following lines of code are in the application's conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with appropriate values for the
account name and access key, respectively.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
243
How to do it...
We are going to show one entity group transaction that inserts two entities in a table and
another entity group transaction that updates one entity and deletes another from the same
table. We will do this using the following steps:
1. Add a new class named EntityGroupTransactionsExample to the project.
2. Install the WindowsAzure.Storage NuGet package and add the following assembly
references to the project:
System.Configuration
3. Add the following using statements to the top of the class le:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System.Configuration;
4. Add the following private members to the class:
private CloudTableClient cloudTableClient;
private String tableName = "Country";
5. Add the following constructor to the class:
public EntityGroupTransactionsExample()
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
cloudTableClient.GetTableReference(tableName)
.CreateIfNotExists();
}
Now, let's proceed with Method1.
6. Add the following method, showing an insert-only entity group transaction, to the class:
public void BatchInsertMethod1()
{
TableServiceContext tableServiceContext =
cloudTableClient.GetTableServiceContext();
CountryDS pakistan = new CountryDS(
"Pakistan", "Islamabad", 171365000);


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
244
tableServiceContext.AddObject(tableName, pakistan);
CountryDS bangladesh = new CountryDS(
"Bangladesh", "Dhaka", 149715000);
tableServiceContext.AddObject(tableName, bangladesh);
tableServiceContext.SaveChangesWithRetries(
SaveChangesOptions.Batch);
}
7. Add the following method, showing a mixed-operation entity group transaction,
to the class:
public void MixedBatchMethod1()
{
TableServiceContext tableServiceContext =
cloudTableClient.GetTableServiceContext();
CountryDS turkey = new CountryDS(
"Turkey", "Istanbul", 72561312);
tableServiceContext.AddObject(tableName, turkey);
CountryDS pakistan = new CountryDS(
"Pakistan", "Islamabad", 171000000);
tableServiceContext.AttachTo(tableName, pakistan, "*");
tableServiceContext.UpdateObject(pakistan);
CountryDS bangladesh = new CountryDS()
{
PartitionKey = "country",
RowKey = "Bangladesh"
};
tableServiceContext.AttachTo(tableName, bangladesh, "*");
tableServiceContext.DeleteObject(bangladesh);
tableServiceContext.SaveChangesWithRetries(
SaveChangesOptions.Batch);
}
Now, let's proceed with Method2.
8. Add the following method, showing an insert-only entity group transaction,
to the class:
public void BatchInsertMethod2()
{
var table = cloudTableClient
.GetTableReference(tableName);
var batch = new TableBatchOperation();
Country italy = new Country(


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
245
"Italy", "Rome", 60000000);
batch.Insert(italy);
Country uk = new Country(
"UK", "London", 63000000);
batch.Insert(uk);
table.ExecuteBatch(batch);
}
9. Add the following method, showing a mixed-operation entity group transaction,
to the class:
public void MixedBatchMethod2()
{
var table = cloudTableClient
.GetTableReference(tableName);
var batch = new TableBatchOperation();
Country germany = new Country(
"Germany", "Berlin", 81000000);
batch.Insert(germany);
Country italy = new Country(
"Italy", "Rome", 61000000) { ETag = "*" };
batch.Replace(italy);
Country uk = new Country(
"UK", "London", 0) { ETag = "*" };
batch.Delete(uk);
table.ExecuteBatch(batch);
}
In both cases, follow this final step.
10. Add the following method, invoking the other methods, to the class:
public static void UseEntityGroupTransactionsExample()
{
EntityGroupTransactionsExample example =
new EntityGroupTransactionsExample();
example.BatchInsertMethod1();
example.BatchInsertMethod2();
example.MixedBatchMethod1();
example.MixedBatchMethod2();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
246
How it works...
In steps 1 through 4, we set up the EntityGroupTransactionsExample class, and in step
5, we created a constructor that initializes the CloudTableClient instance to create a table
specied as an argument.
We then split the recipe into two branches: the rst for Method1 the and second for Method2.
In step 6, we added a BatchInsertMethod1() method. In it, we created a new context.
Then, we created two entities and added them to the context with AddObject(), before
invoking SaveChangesWithRetries (SaveChangesOptions.Batch) to send the
appropriate insert operations to the Table service as a single entity group transaction.
In step 7, we added a MixedBatchMethod1() method. In it, we created a new context and
used it to update one entity and delete another. As we are performing storage operations
on existing entities, we need to take into account the optimistic concurrency provided by the
Table service. We do this using AttachTo() with an ETag of * to have the context track
the entities.
This special ETag value allows us to override the optimistic concurrency
used by the Table service and make it update or delete this entity in the
table. A valid ETag must be provided when updating or deleting objects.
A valid value is the one returned that is with the entity as the result of a
query or the special value of * as in this example.
After attaching the entities, we use UpdateObject() with one entity and DeleteObject()
with the other to indicate which storage operation should be used. Finally, we invoked
SaveChangesWithRetries (SaveChangesOptions.Batch) to send the appropriate
update and delete operations to the Table service as a single entity group transaction.
In step 8, we added a BatchInsertMethod2() method. We used a
TableBatchOperation instance to add, with the Insert() method, two entities into it.
We called the ExecuteBatch() method on the CloudTable instance to send the
appropriate insert operations to the Table service as a single entity group transaction.
In step 9, we added a MixedBatchMethod2() method. We now used two other methods
(Replace() and Delete()) of the TableBatchOperation class, nally committing the
entire operation onto the table. The same considerations of the ETag value * apply to the
second method.
In step 10, we added a method that uses the methods we added in the previous steps.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
247
There's more
While dealing with entity group transactions, remember the following rules:
All entities in a transaction group must have the same PartitionKey value
Multiple PartitionKey values in the same group transaction would throw error
One entity can appear only once and with only one operation as part of the entity
group transactions
See also
Have a look at these MSDN links to get additional information:
Designing a scalable partitioning strategy for the Azure Table storage at http://
msdn.microsoft.com/en-us/library/azure/hh508997.aspx
Implementing retries via the enterprise library at http://msdn.microsoft.com/
en-us/library/hh680934(v=pandp.50).aspx
Using continuation tokens and server-side
paging
The Azure Table service uses partition servers to manage the entities stored in a table.
One partition server manages all the entities with the same PartitionKey value in the
table. However, different partition servers might manage entities with different values
of PartitionKey. This distribution of entities among partition servers is, in general,
transparent to clients of the Table service. This partitioning scheme is central to the
scalability of the Table service.
When processing a query, the Table service submits the query to the rst partition server
(ordered by PartitionKey) that manages entities that satisfy any lter on PartitionKey.
It then returns the rst page of up to 1,000 entities retrieved by the partition server. The
Table service inserts two headers, x-ms-continuation-NextPartitionKey and x-ms-
continuation-NextRowKey(possibly null), into the response if there are additional results.
These headers comprise the continuation tokens for the query.
Any remaining results can be retrieved one page at a time by adding the continuation tokens
as request headers to the query. The Table service uses these continuation tokens to start the
query processing at the correct page. This might be on the current partition server or the next
partition server if the previous query had returned all the entities it managed that matched
the query. The client can reuse the continuation tokens if a previously requested page of data
is needed. This paging functionality is referred to as server-side paging.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
248
Note that it is possible that a query execution returns no entities but does return a
continuation token, which indicates that there are additional results. This can happen if a
query spans multiple partition servers, but the current partition server has found no entities
that match the query.
Handling of continuation tokens is completely transparent to the user in both Method1
and Method2. However, Method1 supports automated handling of continuation tokens
with the TableServiceQuery<T> class, a subtype of DataServiceQuery<T>. If
a large number of entities satisfy a query invoked using a synchronous method of the
TableServiceQuery<T> class, the method might not return for a considerable time.
The AsTableServiceQuery<T>() method in the TableServiceExtensions class
can be used to convert DataServiceQuery<T> into TableServiceQuery<T>.
The TableServiceQuery<T> class supports retries. It also provides synchronous execution
of queries through the Execute() method and asynchronous execution through the
BeginExecuteSegmented() and EndExecuteSegmented() methods.
Method2 supports automatic continuation token handling though the TableQuery class,
and, we should explicitly make a segmented query to avoid this. We go under the hood about
segmented queries in the Going inside continuation tokens and segmented queries recipe.
In this recipe, we will learn how to handle server-side paging.
Getting ready
This recipe uses model classes named Country and CountryDS that are declared in the
Inserting, updating, deleting, and querying data against the Table service recipe. This recipe
also assumes that the following lines of code are in the application's conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with appropriate values for the
account name and access key, respectively.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
249
How to do it...
We are going to invoke a query in two different ways, for both Method1 and Method2. In one,
we do not handle the automatic server-side pagination support, while in the other, we do. We
will proceed as follows:
1. Add a class named ContinuationTokensExample to the project.
2. Install the WindowsAzure.Storage NuGet package and add the following assembly
references to the project:
System.Configuration
3. Add the following using statements to the top of the class le:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System.Configuration;
4. Add the following private members to the class:
private CloudTableClient cloudTableClient;
private String tableName = "Country";
5. Add the following constructor to the class:
public ContinuationTokensExample()
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
cloudTableClient.GetTableReference(tableName)
.CreateIfNotExists();
}
6. Add the following method, uploading 10,000 entities, to the class:
private void Insert10000Rows()
{
var table = cloudTableClient.GetTableReference(tableName);
int counter = 1;
for (int i = 0; i < 100; i++)
{


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
250
var batch = new TableBatchOperation();
for (int j = 0; j <100; j++,counter++)
{
batch.Insert(new Country("Country" + counter,
"Capital", 0));
}
table.ExecuteBatch(batch);
}
}
Now, let's proceed with Method1.
7. Add the following method, using DataServiceQuery, to the class:
private void GetEntitiesNoContinuationMethod1()
{
var ctx=cloudTableClient.GetTableServiceContext();
var res=ctx.CreateQuery<CountryDS>(tableName)
.ToArray();
}
Add the following method, using TableServiceQuery, to the class:
private void GetEntitiesWithContinuationMethod1()
{
var ctx = cloudTableClient.GetTableServiceContext();
var res = ctx.CreateQuery<CountryDS>(tableName)
.AsTableServiceQuery(ctx)
.ToArray();
}
Now, let's proceed with Method2.
8. Add the following method, forcing the segmentation of the query, to the class:
private void GetEntitiesNoContinuationMethod2()
{
var table = cloudTableClient.GetTableReference(tableName);
var res = table.ExecuteQuerySegmented<Country>(
table.CreateQuery<Country>(),null)
.ToArray();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
251
9. Add the following method, handling continuation support, to the class:
private void GetEntitiesWithContinuationMethod2()
{
var table = cloudTableClient.GetTableReference(tableName);
var res = table.CreateQuery<Country>()
.ToArray();
}
In both cases, follow this final step.
10. Add the following method, invoking the other methods, to the class:
public static void UseContinuationTokensExample()
{
ContinuationTokensExample example =
new ContinuationTokensExample();
example.Insert10000Rows();
example.GetEntitiesNoContinuationMethod1();
example.GetEntitiesNoContinuationMethod2();
example.GetEntitiesWithContinuationMethod1();
example.GetEntitiesWithContinuationMethod2();
}
How it works...
In steps 1 through 3, we set up the ContinuationTokensExample class. In step 4,
we added some private members to the class: one that species the name of the Country
table and the other that contains CloudTableClient which we initialize in the constructor
we added in step 5. In step 6, we added 10,000 entities to the Country table. We used
Method2 with 100 batch inserts of 100 entities each (due to the limitation explained in the
Using entity group transactions recipe, as it is the best way to accomplish the task from a
performance perspective.
In step 7, we added a method that uses DataServiceQuery, which does not handle
the continuation tokens returned by the Windows Azure Table service. In step 8, instead,
we obtained the query object through AsTableServiceQuery<T>() to convert it to
TableServiceQuery<T>. We then executed the query asking materialization of entities.
Note that AsTableServiceQuery<T>() is a method in the
TableServiceExtensions class of the Storage library. To let Visual
Studio IntelliSense suggest it, the Microsoft.WindowsAzure.Storage.
Table.DataServices namespace should be added to the code le.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
252
In step 9, we replayed the behavior with Method2, using the new pattern based on the
TableQuery<T> object. As the new pattern natively supports server-side pagination or,
better, it does not have a general-purpose object to deal without it, we need to explicitly
ask for a segmented query to ask for the rst and only chunk of results.
In step 10, we used the same method that, without specifying anything, handles the
server-side pagination that performs several queries on the data store.
To see the behavior of the Storage library, open Fiddler while
executing the methods that handle the pagination to see that
10 consecutive queries are performed against the Table service,
hidden from the user.
In step 11, we added a method that uses the methods we added in the previous steps.
See also
Have a look at the following MSDN link to get additional information:
Reference to the REST implementation of timeout and pagination at http://msdn.
microsoft.com/en-us/library/azure/dd135718.aspx
Going inside continuation tokens and
segmented queries
As we saw in the Using continuation tokens and server-side paging recipe, the Azure Storage
library offers the capability to automatically handle the server-side pagination for queries that
go over some boundaries (more than 1,000 entities, cross partition, and so on). Also, the
library offers, through the concept of segmented queries, the capability to control the query
process deeply, one iteration at a time.
Both Method1 and the Method2 have this capability through the ExecuteSegmented
method of the TableServiceQuery<T> and TableQuery<T> classes, respectively. In
addition, as the Azure Storage library uses the Common Language Runtime (CLR), this
method is also provided with the Asynchronous Programming Model, to provide asynchronous
versions in addition to that method, to nearly all the methods that access the Azure
Storage service. The asynchronous methods that download lists, such as entities, tables,
and so on, typically come in a matched pair named BeginExecuteSegmented () and
EndExecuteSegmented(), where the segmented sufx indicates that the results are
returned as a result segment, which might not contain the complete result set. Essentially,
these methods page through the data, one result segment at a time.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
253
The TableServiceQuery<T> and TableQuery<T> classes expose the
BeginExecuteSegmented() and EndExecuteSegmented() methods to implement the
query execute functionality. The BeginExecuteSegmented() method takes a parameter
that species the current ContinuationToken header along with the callback method
in which EndExecuteSegmented() must be called to clean up resources used in the
asynchronous call. The code can be simplied using a lambda expression in place of the
callback method.
The EndExecuteSegmented() method returns a TableQuerySegment<T> class, which
contains the current page of results (the Results property) as well as any continuation
tokens returned by the Table service. Subsequent synchronous or asynchronous calls to the
same methods should provide them with the ContinuationToken header returned by the
Table service to obtain subsequent pages of data.
In this recipe, we will learn how to manually control the server-side pagination in conjunction
with the use of the APM pattern.
Getting ready
This recipe uses the model classes named Country and CountryDS that are declared
in the Inserting, updating, deleting, and querying data against the Table service recipe and
performs queries on the 10,000-entity dataset uploaded in the Using continuation tokens
and server-side paging recipe. This recipe also assumes that the following lines of code are
in the application's conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with appropriate values for the
account name and access key, respectively.
How to do it...
We are going to execute segmented queries using the asynchronous
BeginExecuteSegmented() and EndExecuteSegmented() methods. We will do this
using the following steps:
1. Add a class named AdvancedContinuationTokensExample to the project.
2. Install the WindowsAzure.Storage NuGet package and add the following
assembly references to the project:
System.Configuration


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
254
3. Add the following using statements to the top of the class le:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System.Configuration;
using System.Threading;
4. Add the following private members to the class:
private CloudTableClient cloudTableClient;
private String tableName = "Country";
5. Add the following constructor to the class:
public AdvancedContinuationTokensExample()
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
cloudTableClient.GetTableReference(tableName)
.CreateIfNotExists();
}
Now, let's proceed with Method1.
6. Add the following private members to the class:
private List<CountryDS> resultsDS = new List<CountryDS>();
private AutoResetEvent loadedDS = new AutoResetEvent(false);
7. Add the following method, demonstrating asynchronous server-side paging, to
the class:
private void ManualContinuationMethod1()
{
var ctx = cloudTableClient.GetTableServiceContext();
TableServiceQuery<CountryDS> query =
ctx.CreateQuery<CountryDS>(tableName)
.AsTableServiceQuery(ctx);
query.BeginExecuteSegmented(null, SegmentedStepMethod1,
query);
loadedDS.WaitOne();
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
255
8. Add the callback method needed by the previous asynchronous call:
private void SegmentedStepMethod1(IAsyncResult obj)
{
var query = obj.AsyncState as TableServiceQuery<CountryDS>;
TableQuerySegment<CountryDS> segmented
= query.EndExecuteSegmented(obj);
resultsDS.AddRange(segmented.Results);
if (segmented.ContinuationToken != null)
{
query.BeginExecuteSegmented(segmented.ContinuationToken
, SegmentedStepMethod1, query);
}
else
{
loadedDS.Set();
}
}
Now, let's proceed with Method2.
9. Add the following private members to the class:
private List<Country> results = new List<Country>();
private AutoResetEvent loaded = new AutoResetEvent(false);
10. Add the following method, demonstrating asynchronous server-side paging,
to the class:
private void ManualContinuationMethod2()
{
var table = cloudTableClient.GetTableReference(tableName);
TableQuery<Country> query = table.CreateQuery<Country>();
query.BeginExecuteSegmented(null, SegmentedStepMethod2,
query);
loaded.WaitOne();
}
11. Add the callback method needed by the previous asynchronous call:
private void SegmentedStepMethod2(IAsyncResult obj)
{
var query = obj.AsyncState as TableQuery<Country>;
TableQuerySegment<Country> segmented
= query.EndExecuteSegmented(obj);
results.AddRange(segmented.Results);
if (segmented.ContinuationToken != null)
{


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
256
query.BeginExecuteSegmented(segmented.ContinuationToken
, SegmentedStepMethod2, query);
}
else
{
loaded.Set();
}
}
In both cases, follow this final step.
12. Add the following method using the methods we added earlier:
public static void UseAdvancedContinuationTokensExample()
{
AdvancedContinuationTokensExample example =
new AdvancedContinuationTokensExample();

example.ManualContinuationMethod1();
example.ManualContinuationMethod2();
}
How it works...
In steps 1 through 3, we set up the ContinuationTokensExample class. In step 4, we added
some private members to the class, one that species the name of the Country table and
the other that contains the CloudTableClient table which we initialized in the constructor we
added in step 5. In step 6, we proceeded with the DataServices pattern, adding two private
members to the class: a list, to save the CountryDS instances returned by the queries, and an
AutoResetEvent class, to block the execution of the asynchronous queries.
In step 7, we created a TableServiceQuery class using the AsTableServiceQuery()
extension method, and we began to execute the asynchronous chain of operations. The
WaitOne() method gets blocked to avoid program termination, and it is intended for
demonstration purposes only.
In step 8, we added the callback method that ends the segmented query, adds the
partial results to the list of items, and reiterates a new segmented query, calling the
BeginExecuteSegmented() method again; this time, it passed a valid continuation
token until it is null, meaning that there are no more entities to fetch from the table.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
257
Steps 9 and 10 are basically the same as 7 and 8, with the exception that with Method2, some
classes change. We used a TableQuery class instead of a TableServiceQuery class, but
the callback method used a TableServiceSegment class for results, as it did for Method1.
In step 12, we added a method that uses the methods we added earlier.
There's more
In the current recipe, we see how to perform segmented queries with the APM pattern.
However, it is possible to perform these queries in a synchronous way as follows:
private void ManualContinuationMethod2Sync()
{
var table = cloudTableClient.GetTableReference(tableName);
TableQuery<Country> query = table.CreateQuery<Country>();
TableContinuationToken token=null;
var list=new List<Country>();
do
{
var res = query.ExecuteSegmented(token);
token = res.ContinuationToken;
list.AddRange(res.Results);
} while (token != null);
}
As shown in the code snippet, we cycle over a ContinuationToken condition to check if
there is more data to fetch from the Table service.
See also
We will see how to use the Storage Client library to download blobs asynchronously in the
Downloading a blob asynchronously recipe of Chapter 3, Getting Storage with Blobs in Azure.
Have a look at this MSDN link to get additional information:
The Azure Table storage while implementing Cloud solutions at http://msdn.
microsoft.com/en-us/library/ff803362.aspx


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
258
Handling entity serialization events
The Azure Table service exposes a RESTful interface in which an entity is represented in
various formats. Initially, there was only the Atom format to support JSON in recent years.
In saving an instance to a table, the Azure Storage library serializes the instance into the
appropriate format before invoking the appropriate REST operation on the Table service.
Similarly, when retrieving an entity from a table, the Storage Client library deserializes the
entry into an instance of the model class.
The Table service supports a limited set of simple datatypes for the properties of entities.
These datatypes are listed in the Inserting, updating, deleting, and querying data against the
Table Service recipe. By default, the Storage Client library serializes an instance of a model
class by converting each public property of one of the supported datatypes into an element
in a result entry. Deserialization simply reverses this process.
Method1 and Method2 differ dramatically in how deserialization can be controlled or
inuenced. The rst method, based on WCF Data Services, allows us to operate on the
TableServiceContext conguration to intercept serialization events in the request
pipeline. The second one passes the control of serialization events to the entity involved
in the process.
In this recipe, we will learn how to inuence the serialization events to modify the default
serialization and deserialization behaviors when saving and retrieving data from a table.
Getting ready
This recipe assumes that the following lines of code are in the application's conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with appropriate values for the
account name and access key, respectively.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
259
How to do it...
We are going to create model classes to represent cars, books, and customers. We want to
save these entities in the same table while marking the items with their type, to perform a
ltered retrieval subsequently. We will proceed with the two methods separately, as they
differ a lot:
1. Add a class named ReadingWritingEntityExample.
2. Install the WindowsAzure.Storage NuGet package and add the following assembly
references to the project:
System.Configuration
3. Add the following using statements to the top of the class le:
using Microsoft.Data.OData;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Table.DataServices;
using System.Configuration;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Services.Client;
using System.Xml.Linq;
4. Add the following private members to the class:
private CloudTableClient cloudTableClient;
private String tableName = "Stuff";
5. Add the following constructor to the class:
public ReadingWritingEntityExample()
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
cloudTableClient.GetTableReference(tableName)
.CreateIfNotExists();
}
Now, let's proceed with Method1.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
260
6. Add the BaseEntityDS class to the code after the namespace declaration:
public class BaseEntityDS : TableServiceEntity
{
public string Type { get; set; }
public BaseEntityDS()
{
PartitionKey = "variousDS";
}
}
7. Add the model classes after the preceding class declaration:
public class CarDS : BaseEntityDS
{
public string Brand { get; set; }
}
public class BookDS : BaseEntityDS
{
public string Author { get; set; }
}
public class CustomerDS : BaseEntityDS
{
public string Name { get; set; }
}
8. Add this method, performing a 100-entity bulk insert, to the class:
private void AddSomeEntitiesMethod1()
{
var ctx = cloudTableClient.GetTableServiceContext();
ctx.Configurations.RequestPipeline.OnEntryEnding(a =>
{
var typeName = a.Entity.GetType().Name;
var props = a.Entry.Properties.ToList();
var type = props
.FirstOrDefault(p => p.Name == "Type");
if (type == null)
{
type = new ODataProperty() { Name = "Type" };
props.Add(type);
a.Entry.Properties = props;
}
type.Value = typeName;
});
int counter = 1;
for (int i = 0; i < 100; i++)


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
261
{
BaseEntityDS entity = null;
if (counter == 1) entity =
new CarDS() { Brand = "BMW" + i,
RowKey = i.ToString() };
if (counter == 2) entity =
new BookDS() { Author = "Whitman" + i,
RowKey = i.ToString() };
if (counter == 3) entity =
new CustomerDS() { Name = "Steve" + i,
RowKey = i.ToString() };
counter = (counter == 3 ? 1 : counter + 1);
ctx.AddObject("Stuff", entity);
}
ctx.SaveChangesWithRetries(SaveChangesOptions.Batch);
}
9. Add this method, reading only certain type of entities, to the class:
public void ReadingEntitiesMethod1()
{
var ctx = cloudTableClient.GetTableServiceContext();
var res = ctx.CreateQuery<CarDS>("Stuff")
.Where(p => p.Type == "CarDS")
.ToArray();
}
Now, let's proceed with Method2.
10. Add the BaseEntity class to the code after the namespace declaration:
public class BaseEntity:TableEntity
{
public string Type { get; set; }
public BaseEntity()
{
PartitionKey = "various";
}
public override IDictionary<string, EntityProperty>
WriteEntity(OperationContext operationContext)
{
var dict= base.WriteEntity(operationContext);
dict["Type"]= new EntityProperty(this.GetType().Name);
return dict;
}
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
262
11. Add the model classes after the preceding class declaration:
public class Car : BaseEntity
{
public string Brand { get; set; }
}
public class Book : BaseEntity
{
public string Author { get; set; }
}
public class Customer : BaseEntity
{
public string Name { get; set; }
}
12. Add this method, performing a 100-entity bulk insert, to the
ReadingWritingEntityExample class:
public void AddSomeEntitiesMethod2()
{
var table = cloudTableClient
.GetTableReference(tableName);
int counter = 1;
var batch = new TableBatchOperation();
for (int i = 0; i < 100; i++)
{
BaseEntity entity = null;
if (counter == 1) entity =
new Car() { Brand = "BMW"+i,
RowKey = i.ToString() };
if (counter == 2) entity =
new Book() { Author = "Whitman"+i,
RowKey = i.ToString() };
if (counter == 3) entity =
new Customer() { Name= "Steve"+i,
RowKey = i.ToString() };
counter=(counter==3?1:counter+1);
batch.Insert(entity);
}
table.ExecuteBatch(batch);
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
263
13. Add this method, reading only certain type of entities, to the class:
public void ReadingEntitiesMethod2()
{
var table = cloudTableClient.GetTableReference(tableName);
var res = table.CreateQuery<Car>().Where(p=>p.Type=="Car")
.ToArray();
}
In both cases, follow this final step.
14. Add the following method using the methods we added earlier:
public static void UseReadingWritingEntityExample()
{
ReadingWritingEntityExample example =
new ReadingWritingEntityExample();
example.AddSomeEntitiesMethod1();
example.ReadingEntitiesMethod1();
example.AddSomeEntitiesMethod2();
example.ReadingEntitiesMethod2();
}
How it works...
In steps 1 through 3, we set up the ReadingWritingEntityExample class. In step 4,
we added some private members to the class: one that species the name of the Stuff
table and the other that contains the CloudTableClient class which we initialize in the
constructor we added in step 5.
In step 6, we proceeded with the DataServices pattern, creating a BaseEntityDS father
type, writing its instances to the variousDS partition. In step 7, we added the CarDS,
BookDS, and CustomerDS subtypes. As done with the Country data model (of the previous
recipes), we wrote two separate models to deal independently from Method1 and Method2.
In step 8, we added 100 entities to the Stuff table, using an index technique to equally
distribute them across subtypes. Before invoking the SaveChangesWithRetries()batch,
we injected a custom serialization function in RequestPipeline to make it called each time
the TableServiceContext class tried to serialize an entity before sending it to the cloud.
Hence, we asked for the properties being serialized, and we injected the Type eld to the
entity type name. We needed to reassign the Properties property of the Entry instance
due to the (IEnumerable<ODataProperty>) property type that is not editable.
In step 9, we made a simple query that performed a lter onto the Type property, to retrieve
only the entities that are of the CarDS type.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
264
In step 10, we proceeded with the new pattern, declaring a base entity type (writing to
the various partition), which directly handled its serialization logic by overriding the
WriteEntity method of the TableEntity type. The semantic of this method is to inuence
a dictionary of properties before returning it to the storage library. So, it is quite simple to add
the interested property to the dictionary and return it.
As done for Method1, in step 11, we added the car, book, and customer subtypes to the
code, and we added 100 entities of mixed types in step 12. The batch operation performed a
single query with the whole dataset, as explained better in the Using entity group transactions
recipe. Finally, in step 13, we used CloudTable.CreateQuery<T> to perform a query,
ltered by the type we are interested in.
In step 14, we added a method that uses the methods we added earlier.
There's more
As we can imagine, as we deal with the event during serialization, we can even handle the
event during the deserialization process. With WCF Data Services, we can inuence the entire
RequestPipeline property to t our needs of customization. In particular, we have to
handle these events as follows:
public class DataServiceClientRequestPipelineConfiguration
{
public Func<DataServiceClientRequestMessageArgs,
DataServiceClientRequestMessage> OnMessageCreating { get; set;
}
public DataServiceClientRequestPipelineConfiguration
OnEntityReferenceLink(Action<WritingEntityReferenceLinkArgs>
action);
public DataServiceClientRequestPipelineConfiguration
OnEntryEnding(Action<WritingEntryArgs> action);
public DataServiceClientRequestPipelineConfiguration
OnEntryStarting(Action<WritingEntryArgs> action);
public DataServiceClientRequestPipelineConfiguration
OnMessageWriterSettingsCreated(Action<MessageWriterSettingsAr
gs> args);
public DataServiceClientRequestPipelineConfiguration
OnNavigationLinkEnding(Action<WritingNavigationLinkArgs>
action);
public DataServiceClientRequestPipelineConfiguration
OnNavigationLinkStarting(Action<WritingNavigationLinkArgs>
action);
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
265
During the response, when the entities are deserialized from the HTTP stream, we have these
events too:
public class DataServiceClientResponsePipelineConfiguration
{
public DataServiceClientResponsePipelineConfiguration
OnEntityMaterialized(Action<MaterializedEntityArgs> action);
public DataServiceClientResponsePipelineConfiguration
OnEntryEnded(Action<ReadingEntryArgs> action);
public DataServiceClientResponsePipelineConfiguration
OnEntryStarted(Action<ReadingEntryArgs> action);
public DataServiceClientResponsePipelineConfiguration
OnFeedEnded(Action<ReadingFeedArgs> action);
public DataServiceClientResponsePipelineConfiguration
OnFeedStarted(Action<ReadingFeedArgs> action);
public DataServiceClientResponsePipelineConfiguration
OnMessageReaderSettingsCreated(Action<MessageReaderSettingsAr
gs> messageReaderSettingsAction);
public DataServiceClientResponsePipelineConfiguration
OnNavigationLinkEnded(Action<ReadingNavigationLinkArgs>
action);
public DataServiceClientResponsePipelineConfiguration
OnNavigationLinkStarted(Action<ReadingNavigationLinkArgs>
action);
}
With the new pattern, we can override the ReadingEntity method in each son of the
TableEntity type. This lets us customize the deserialization process; this is very useful
while dealing with third-party objects nested in our model classes.
Legacy approach to custom serialization with Atom feeds
The Storage Client library exposes extension points, the WritingEntity and
ReadingEntity events, that can be used to modify the default behavior of serialization and
deserialization, but only while using an XML Atom feed as the negotiating format. An argument
of the ReadingWritingEntityEventArgs type is passed into the WritingEntity and
ReadingEntity handlers. This argument provides access to both the instance properties,
and the Atom entry allows them to be inspected and modied as desired.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
266
The following is an excerpt of how to deal with that:
var ctx = cloudTableClient.GetTableServiceContext();
XNamespace ns = ctx.DataNamespace;
XNamespace meta = ctx.DataNamespace + "/metadata";
ctx.Format.UseAtom();
ctx.WritingEntity += (s, e) =>
{
var entity = e.Entity as BaseEntityDS;
entity.Type = entity.GetType().Name;
XElement properties = e.Data.Descendants(
meta + "properties").First();
properties.Add(new XElement(ns + "Type", entity.Type));
};
As we can see, this kind of customization involves the specic format, and it is
generally deprecated.
See also
We learned about the data model used by the Table service in the Inserting, updating,
deleting, and querying data against the Table service recipe.
Have a look at the following MSDN links to get additional information:
Performance considerations with Table storage, serialization, and JSON at
http://blogs.msdn.com/b/windowsazurestorage/archive/2013/12/05/
windows-azure-tables-introducing-json.aspx
AtomPub specications at http://msdn.microsoft.com/en-us/library/
dd541369.aspx
Facilitating NoSQL with client-side
projection
The Azure Table service is a powerful storage service that enables an application to save and
query entities (potentially schemaless) with an unbelievable scalability target and, of course,
minimal governance. As we can save several types of aggregates of different topologies into
the same table, the Storage library helps us deal with this, performing client-side projection
to provide the application with the strong-typed model, instead of a collection of key-value
items for each entity.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
267
In this chapter, we wrote about two different ways to accomplish tasks
with the Table service. We called them Method1 (for the WCF Data
Services way) and Method2 (for the new ofcially supported OData
method). In this recipe, we will only show how to proceed with Method2,
as there are no valid counterparts to Method1.
In this brief recipe, we will see how to notice the SDK to manipulate returning entities
before giving them back to the application.
Getting ready
This recipe uses the BaseEntity, Car, Book, and Customers classes dened in the
Handling entity serialization events recipe. Although a complete reading of the recipe
is useful to proceed, only the class model is needed to proceed.
This recipe also assumes that the following lines of code are in the application's
conguration le:
<appSettings>
<add key="DataConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={ACCOUNT_
NAME};AccountKey={ACCOUNT_KEY}"/>
</appSettings>
We must replace {ACCOUNT_NAME} and {ACCOUNT_KEY} with appropriate values for
the account name and access key, respectively.
How to do it...
We are going to query the DynamicStuff table to obtain each entity, but as they are
different in type and properties, we want a client-side resolver that wraps each entity
into the correct class type. We will proceed as follows:
1. Add a class named ClientSideProjectionExample.
2. Install the WindowsAzure.Storage NuGet package and add the following
assembly references to the project:
System.Configuration
3. Add the following using statements to the top of the class le:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using System.Configuration;
using System.Collections.Generic;
using System.Configuration;


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
268
4. Add the following private members to the class:
private CloudTableClient cloudTableClient;
private String tableName = "DynamicStuff";
5. Add the following constructor to the class:
public ClientSideProjectionExample()
{
CloudStorageAccount cloudStorageAccount =
CloudStorageAccount.Parse(
ConfigurationManager.AppSettings[
"DataConnectionString"]);
cloudTableClient =
cloudStorageAccount.CreateCloudTableClient();
cloudTableClient.GetTableReference(tableName)
.CreateIfNotExists();
}
6. Add the following method, to wrap each entity into the correct type, to the class:
public IEnumerable<BaseEntity> GetAllItemsByType()
{
var table = cloudTableClient.GetTableReference(tableName);
EntityResolver<BaseEntity> resolver =
(pk, rk, ts, props, etag) =>
{
BaseEntity resolvedEntity = null;
string type = props["Type"].StringValue;
if (type == "Car") { resolvedEntity = new Car(); }
else if (type == "Book") { resolvedEntity = new Book(); }
else if (type == "Customer") { resolvedEntity
= new Customer(); }
resolvedEntity.PartitionKey = pk;
resolvedEntity.RowKey = rk;
resolvedEntity.Timestamp = ts;
resolvedEntity.ETag = etag;
resolvedEntity.ReadEntity(props, null);
return resolvedEntity;
};
return table.ExecuteQuery(table
.CreateQuery<BaseEntity>(), resolver);
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
269
7. Add the following method using the method we added earlier to print only the brand
values of the Car entities:
public static void UseReadingWritingEntityExample()
{
ClientSideProjectionExample example =
new ClientSideProjectionExample();
var items = example.GetAllItemsByType();
foreach (var item in items.OfType<Car>())
{
Console.WriteLine(item.Brand);
}
}
How it works
In steps 1 through 3, we set up the ClientSideProjectionExample class. In step 4,
we added some private members to the class: one that species the name of the Stuff
table and the other that contains the CloudTableClient class which we initialized in the
constructor we added in step 5.
In step 6, we created an EntityResolver<BaseEntity> instance, specifying that for
each entity retrieved from the data store, a lambda must be called to handle a custom
resolving logic. In the code, we discriminated the Type eld to create a specic instance
of the correct type. Then, we called the underlying deserialization logic with the
TableEntity.ReadEntity method.
In step 7, we got all the items of the data store, and then, we used LINQ to cycle only the
Car instances.
There's more
There is really no need to build our custom data model to t the Azure Table service. Instead,
we can just work with a top-level implementation of TableEntity that wraps the entire
content of an entity into a set of key-value items.
The DynamicTableEntity class is returned by the Storage library when the query is not
bound to an actual type, so the library can't deserialize the entity into a custom object. With
the DynamicTableEntity class, we can deal with heterogeneous queries, as it extends
the TableEntity base class with heterogeneous updates as well.


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Going NoSQL with Azure Tables
270
To perform a generic query for all the elements in a specic partition, proceed as follows:
public IEnumerable<DynamicTableEntity> GetHeterogeneousItems()
{
var table = cloudTableClient.GetTableReference(tableName);
return table.ExecuteQuery(new TableQuery()
.Where(TableQuery.GenerateFilterCondition
("PartitionKey",QueryComparisons.Equal,"various")));
}
Please note that the Where clause of the nongeneric TableQuery class does not have the
LINQ expressions' overloads to use lambda for lters. Instead, it has a simple string-based
query language (the OData language) that could also be generated using the TableQuery
static helper members and the QueryComparisons helper class.
Each item of the returned set has the base properties of each TableEntity class plus
every other property stored in an IDictionary<string,EntityProperty> property,
and it is accessible as follows:
var heterogenous = example.GetHeterogeneousItems();
foreach (var item in heterogenous)
{
Console.WriteLine(item["Type"].StringValue);
}
Finally, to perform a batch update of the heterogeneous entities, we can use the following
line of codes:
public void PerformHeterogeneousUpdate(IEnumerable<DynamicTableEntity>
set)
{
var table = cloudTableClient.GetTableReference(tableName);
TableBatchOperation batch = new TableBatchOperation();
foreach (var item in set)
{
item["NewField"] =new EntityProperty("Hi");
batch.Merge(item);
}
table.ExecuteBatch(batch);
}


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Chapter 5
271
See also
Have a look at these MSDN links to get additional information:
Comparison between the Azure Table storage and Azure SQL Database at http://
msdn.microsoft.com/en-us/library/jj553018.aspx
The NoSQL perspective around the Table storage at http://msdn.microsoft.
com/en-us/magazine/dn166928 .aspx


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

Where to buy this book
You can buy Microsoft Azure Development Cookbook Second Edition from the Packt
Publishing website:
.
Free shipping to the US, UK, Europe and selected Asian countries. For more information, please
read our shipping policy.
Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and
most internet book retailers.



















www.PacktPub.com


For More Information:
www.packtpub.com/microsoft-azure-development-cookbook/book

You might also like