Azure编程笔记(1):序列化复杂类型的TableEntity字段


内容提要

在使用MicrosoftAzureCloudTable存储数据时,我们先要把数据定义成TableEntity的子类。如果TableEntity中包含复杂类型(比如容器类型如List等、或者自定义类型)的字段,这些字段需要自己做序列化才能保存到CloudTable中去。

问题描述

我们模拟社交网站定义一个类型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>();
    }
}

为了简化问题,在存储时所有账号的PartitionKey都一样,RowKey是账号的Email邮箱。接下来我们用如下代码添加两个用户,并把他们互相加为好友:

static void TestAddAccount()
{
    string connectionString = Constant.connectionString;
    var storageAccount = Utilities.GetStorageAccount(connectionString);
    var accountsTable = new AccountsTableWrapper(storageAccount);

    string email1 = "harryhe@hotmail.com";
    string nickName1 = "Harry He";
    accountsTable.AddAccount(email1, nickName1);

    string email2 = "peterwang@hotmail.com";
    string nickName2 = "Peter Wang";
    accountsTable.AddAccount(email2, nickName2);

    accountsTable.AddFriend(email1, email2);
}


当我们用工具AzureStorage Explorer查看CloudTable中的数据,我们发现表格中没有好友列表对应列,如下图所示:


看起来用来表示好友列表的字段List<string>Friends没有存储到CloudTable中去。

问题根源

目前TableEntity在缺省情况下只支持简单类型,如数值(intfloat等)、布尔值、字符串、DateTime等。对于自定义的复杂类型、数据容器类型(如例子中的List)、枚举类型等,只有在序列化之后才能正确地存储到CloudTable中去。

解决问题

我们可以重载TableEntity的两个函数ReadEntityWriteEntity,把字段Friends序列化成XML格式的字符串,这样该字段就能保存到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;
}

如果我们再次添加两个互为好友的账号,通过AzureStorage Explorer可以看出CloudTable里的数据如下图所示:


附录


实现序列化的类型SerializeWrapper如下所示:

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;
    }
}




相关内容

    暂无相关文章