Contents
When using microsoftazure's cloudtable to store data, we must first define the data as a subclass of tableentity. Suppose that tableentity contains complex types (for example, container types such as list, or custom types), these fields must be serialized to be saved to cloudtable.
Problem description
A simulated social media site defines a type of account, which includes the basic information of an account, such as the email address, name, and birthday. At the same time, it also includes a list of friends of an account:
public class Account : TableEntity{ public const string AccountsPartitionKey = "AccountsPartition"; private const string FriendsKeyName = "Friends"; public string NickName { get; set; } public List<string> Friends { get; set; } public Account() { } public Account(string email, string nickName) { this.PartitionKey = AccountsPartitionKey; this.RowKey = email; this.NickName = nickName; this.Friends = new List<string>(); }}
To simplify the problem, the partitionkeys of all accounts are the same during storage, and rowkey is the account's email address. Next we will use the following code to add? Two users, and add them as friends:
static void TestAddAccount(){ string connectionString = Constant.connectionString; var storageAccount = Utilities.GetStorageAccount(connectionString); var accountsTable = new AccountsTableWrapper(storageAccount); string email1 = "[email protected]"; string nickName1 = "Harry He"; accountsTable.AddAccount(email1, nickName1); string email2 = "[email protected]"; string nickName2 = "Peter Wang"; accountsTable.AddAccount(email2, nickName2); accountsTable.AddFriend(email1, email2);}
When we use the tool azurestorage explorer to view the data in cloudtable, we find that the table does not have the corresponding columns of the friend list, as shown in the following figure:
The list <string> friends field used to represent the friend list is not stored in cloudtable.
Root Cause
Currently, tableentity only supports simple types by default, such as values (INT, float, etc.), Boolean values, strings, and datetime. For custom complex types, data container types (such as list in the example), and enumeration types, only after serialization can they be correctly stored in cloudtable.
Solve this problem
We can reload the two functions readentity and writeentity of tableentity to serialize the field friends into a string in XML format, so that the field can be saved to cloudtable.
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext){ base.ReadEntity(properties, operationContext); foreach (var item in properties) { if (item.Key == FriendsKeyName) { var serializer = new SerializeWrapper<List<string>>(); string serializedFriends = item.Value.StringValue; this.Friends = serializer.Deserialize(serializedFriends); } }}public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext){ var results = base.WriteEntity(operationContext); var serializer1 = new SerializeWrapper<List<string>>(); string serializedFriends = serializer1.Serialize(this.Friends); results.Add(FriendsKeyName, new EntityProperty(serializedFriends)); return results;}
Suppose we join again? The two accounts are mutual friends. azurestorage explorer shows the data in cloudtable as shown in the following figure:
Appendix
Serializewrapper of the serialization type, as shown in the following figure:
public class SerializeWrapper<T>{ private XmlSerializer xmlSerializer; public SerializeWrapper() { xmlSerializer = new XmlSerializer(typeof(T)); } public string Serialize(T item) { string output; using (var sw = new StringWriter()) { xmlSerializer.Serialize(sw, item); output = sw.ToString(); } return output; } public T Deserialize(string message) { T item; using (var sr = new StringReader(message)) { item = (T)xmlSerializer.Deserialize(sr); } return item; }}
Zookeeper