Using PartitionKey and RowKey to Organize the Data to be Distributed In order to support load balancing, tables and therefore entities in the cloud are partitioned across storage nodes
Trang 1Listing 1-8 The Context Query Class Derived from TableStorageDataServiceContext Implemented in a Data Table Storage
public class UserDataContext : TableStorageDataServiceContext
{
public DataServiceQuery<Address> AddressTable
{
get
{
CreateQuery<Address>(ConfigurationManager.AppSettings["AddressTable"]); }
}
}
■ Note The compiler does not provide detailed information about why the data storage generation failed
Hopefully, the information will be available from Microsoft in future releases
Using PartitionKey and RowKey to Organize the Data to be
Distributed
In order to support load balancing, tables and therefore entities in the cloud are partitioned across storage nodes, which may be physically located in different servers Each partition holds a consecutive range of entities that have the same partition key value, which is how partitions are organized As noted above, we specify the partition key as the PartitionKey property in a table, and it must be unique to allow for consecutive ordering into partitions This sounds familiar, because the partition key forms part
of an entity’s primary key in combination with RowKey
The data can be organized based on the usage of PartitionKey and RowKey for each data table entity
By design, the values for both PartitionKey and RowKey could be empty strings, whereas null values are not allowed Table 1-2 below shows possible combinations of PartitionKey and RowKey
Table 1-2 Using PartitionKey and RowKey to Organize the Table Structures
PartitionKey RowKey Usage Conditions
Empty string Empty string One partition or one row
Has value Empty string Multiple partitions or one row
Empty string Has value One partition or multiple rows per a partition
Has value Has value Multiple partitions of multiple rows for each partition
Trang 2Create Cloud Data Storage with Relational Data Structure
Migrating existing relational data storage from an on-premises system to a cloud environment is a really interesting topic and a challenge for an organization to face There are a variety of good answers and
solutions In this exercise, we are going to create data storage with a relational structure among data
entities to provide you with a starting point SQL Azure provides a ready-made solution for relational
data storage infrastructure and is covered in Chapter 8 The rest of this chapter will provide an example exercise to handle a simple relational data structure that runs in a cloud using table storage, as you may not want the full-blown SQL Azure service
The data structure we will build includes three data entities: Address, Person, and User The
Address data entity is the same as the one we created in the first exercise A Person data entity has an encapsulated object Address A User data entity has an encapsulated object Person In terms of the
XML schema, the relationship among these entities can be understood as the reference of one schema
to another, such as a User reference to Person and a Person reference to Address This is a typical
example using an object-oriented approach to data modeling and schema definitions Figure 1-14 and Figure 1-15 provide the relationship in terms of XML schemas
Figure 1-14 User data structure schemas
Trang 3As explained in the previous exercise, we cannot use the property access attribute to expose an embedded object from an entity class We either have to alter the embedded object as we did previously
or use methods to provide access to the internal objects Otherwise, the data table generation fails and the compiler does not provide the specific reason Listing 1-9 shows how to expose a custom-defined inner data entity object from a data object class using class member methods instead of member attributes
Listing 1-9 Using a Member Method Instead of Member Attributes to Expose Inner Data Entity Objects of
a Non-portable Custom-defined Type
public class Person : TableStorageEntity
{
private Address _address = null;
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleInitial { get; set; }
public string Suffix { get; set; }
public Address GetAddress() { return _address; }
}
Following the same procedures as we had in the first exercise, we successfully generated three data tables from local cloud data storage as the screenshot shows in Figure 1-16
Figure 1-16 Generated relational data storage
From this example, we learned that data entity classes with relational structures in a cloud platform have some limitations If an entity class has a dependency entity class, property attributes cannot be used for access Instead, member methods should be used It should be borne in mind that you need to refactor existing data storage for the cloud We will discuss more refactoring issues in later chapters
Trang 4A Constraint for Data Entity Classes Contains Embedded Entity
Classes
Today, a lot of existing software uses data entity classes generated from XML schemas using the NET utility Xsd.exe shipped with the NET Framework By default, the generated data entity classes using Xsd.exe use a property attribute function to access the embedded data entity objects When we
refactor existing code to a cloud platform, we can simply derive these data entity classes from
TableStorageEntity However, all property functions used to expose embedded data object from a
container or parent class must be refactored to Get/Set member method pairs instead
Listing 1-10 shows the data entity class for Person generated by using Xsd.exe All attribute
properties such as the AddressRoot, as highlighted in Listing 1-9, must be reimplemented as Get/Set
member method pairs
Listing 1-10 The Person Class Generated from Xsd.exe Using the XML Schemas
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true,
Namespace="http://AzureForDotNetDeveloper.Schema.User.Person")]
[System.Xml.Serialization.XmlRootAttribute
(Namespace="http://AzureForDotNetDeveloper.Schema.User.Person", IsNullable=false)]
public partial class PersonRoot {
private string firstNameField;
private string latNameField;
private string middleInitialField;
private string suffixField;
private AddressRoot addressRootField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute
(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string FirstName {
get {
return this.firstNameField;
}
set {
this.firstNameField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(
Namespace="http://AzureForDotNetDeveloper.Schema.User.Address")]
public AddressRoot AddressRoot {
get {
Trang 5set {
this.addressRootField = value;
}
}
}
Refactoring Data Entity Classes
A solution to the constraint for data entity classes containing embedded entity classes is to refactor To refactor the PersonRoot class for Windows Azure platform, follow these steps:
1 Add using Microsoft.Samples.ServiceHosting.StorageClient; into the project
2 Make the PersonRoot class derive from the TableStorageEntity class
3 Modify the Get/Set property pair into the GetAddress()/SetAddress() method
pair Listing 1-11 shows the results after the Person data entity class has been
refactored
Listing 1-11 Refactoring the Person Class to the Azure Cloud Platform
using Microsoft.Samples.ServiceHosting.StorageClient;
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true,«
Namespace="http://AzureForDotNetDeveloper.Schema.User.Person")]
[System.Xml.Serialization.XmlRootAttribute(Namespace=«
"http://AzureForDotNetDeveloper.Schema.User.Person", IsNullable=false)]
public partial class PersonRoot : TableStorageEntity
{
public AddressRoot GetAddressRoot()
{
return this.addressRootField;
}
public void SetAddressRoot(AddressRoot address)
{
this.addressRootField = address;
}
}