实现 Azure Table 的 ITable 实体接口以支持嵌套对象和自定义 属性 类型

Implementing Azure Table's ITableEntity interface to support nested objects and custom property types

Azure Table 存储仅支持基本数据类型,如 (int、string、Guid、DateTime) 等。这使得很难存储本身包含对象的对象,即嵌套对象。也不支持直接存储List<>等集合数据类型

为此,我创建了一个继承自 ITableEntity 的 CustomEntity class,并使用新引入的 TableEntity.Flatten(...)TableEntity.ConvertBack<TResult>(...) 方法实现了 ReadEntity 和 WriteEntity 方法.我现在只专注于存储嵌套对象。

public class CustomEntity : ITableEntity
{
    // Partition Key, Row Key, Timestamp and ETag here

    public void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
    {
        CustomEntity customEntity = TableEntity.ConvertBack<CustomEntity>(properties, operationContext);
        // Do the memberwise clone for this object from the returned CustomEntity object
        CloneThisObject(this, customEntity);
    }

    public IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
    {
        IDictionary<string, EntityProperty> flattenedProperties = TableEntity.Flatten(this, operationContext);
        flattenedProperties.Remove("PartitionKey");
        flattenedProperties.Remove("RowKey");
        flattenedProperties.Remove("Timestamp");
        flattenedProperties.Remove("ETag");
        return flattenedProperties;
    }
}

我在我的模型中使用了上面的代码,并且能够在 Azure 表中成功插入一个嵌套对象。当我想检索同一个对象时,问题就来了。代码在 table.Execute(TableOperation.Retrieve(partitionKey, rowKey)) 命令处陷入无限循环。

此外,虽然在 CustomEntity 对象的插入操作期间命中了 WriteEntity 代码,但在检索实体时未命中 ReadEntity 代码。我在这里错过了什么?任何帮助将不胜感激。

the ReadEntity code isn't hit while retrieving the entity.

table.Execute(TableOperation.Retrieve(partitionKey, rowKey)) 方法将 return 一个 DynamicTableEntity。它不会调用您定义的 ReadEntity 方法。如果您执行如下查询,将命中 ReadEntity 方法。

var  entity = table.Execute(TableOperation.Retrieve<CustomEntity>(partitionKey, rowKey)).Result;

我创建了一个通用方法,可以帮助您获取具有嵌套对象的实体,下面的代码供您参考。

public static List<T> GetEntities<T>(CloudTable table, string filter) where T : ITableEntity, new()
{
    List<T> entities = new List<T>();

    DynamicTableEntity dynamicTableEntity = new DynamicTableEntity();

    dynamicTableEntity.Properties = TableEntity.Flatten(new T(), new OperationContext());

    TableQuery<DynamicTableEntity> projectionQuery = new TableQuery<DynamicTableEntity>().Where(filter);
    foreach (var dEntity in table.ExecuteQuery(projectionQuery))
    {
        T entity = EntityPropertyConverter.ConvertBack<T>(dEntity.Properties, new OperationContext());

        entity.PartitionKey = dEntity.PartitionKey;
        entity.RowKey = dEntity.RowKey;
        entity.ETag = dEntity.ETag;
        entity.Timestamp = dEntity.Timestamp;

        entities.Add(entity);
    }
    return entities;
}

这里是测试代码。

嵌套对象定义。它继承自 post.

中定义的 CustomEntity
public class EmployeeEntity : CustomEntity
{
    public EmployeeEntity(string lastName, string firstName)
    {
        this.PartitionKey = lastName;
        this.RowKey = firstName;
    }

    public EmployeeEntity() { }

    public string Email { get; set; }

    public Address ContactAddress { get; set; }
}

public class Address
{
    public string Province { get; set; }

    public string City { get; set; }
}

从 table 获取员工实体。

CloudTable table = tableClient.GetTableReference("tableName");
var entities = CustomEntity.GetEntities<EmployeeEntity>(table, "PartitionKey eq 'pk'"); 

可能有点晚了,但我想更新答案,因为这可以解决您的问题。我更新了 Object Flattener Recomposer api 以支持 IEnumerable/ICollection 类型属性。基本上,您可以使用 Object Flattener Recomposer api 的 v2.0 将几乎任何内容写入 table 存储: https://www.nuget.org/packages/ObjectFlattenerRecomposer/

api 透明地处理所有 transformations/serializations 和反序列化,因此无需编写您自己的逻辑。