使用Array或List属性创建TableEntity?

时间:2017-08-05 01:48:55

标签: azure-table-storage azure-tablequery

我在Azure表中存储了一些这样的枚举

pk   rk |    en     fr     de   ...

foo  1  |  'Eune' 'Fune' 'Dune' ...
foo  2  |  'Edoe' 'Fdoe' 'Ddoe' ...

bar  1  |  'Unee' 'Unef' 'Trid' ...
bar  2  |  'Diee' 'Dief' 'Died' ...
bar  3  |  'Trie' 'Tref' 'Trid' ...

enfrde等...是语言代码,分别是表格中的列名称。

我应该创建哪种TableEntity才能正确加载

public class FooEntity : TableEntity
{
    public Dictionary<string, string> Descriptions {get; set} // ?
}

然后像myFoo["fr"]一样使用它们......有可能吗?

假设我有英文GUI,我需要显示Foo选择Eune / Edoe作为选择值。

4 个答案:

答案 0 :(得分:6)

我的回答扩展了Zhaoxing将复杂实体属性编写为JSON并将其持久保存到Azure CosmosDB的方法。

但是,setter中字符串和对象之间的序列化会导致以下问题:

  1. 例如,如果您要在字典DicProperty中添加或删除项目,则不会调用其setter,因为您尚未修改字典但已修改其内容。同样,在您对序列化自定义对象或类感兴趣的更复杂的用例中,修改类的成员将不会触发setter。当实体提交到CloudTable时,这可能导致数据丢失。
    1. 如果您确实选择在复杂属性上实现类似INotifyPropertyChanged的内容,可以使用某种形式的ObservableCollection或自己执行事件通知,最终会序列化和反序列化太多次。这也是整个模型中太多代码的用处。
  2. 相反,我重写了TableEntity的WriteEntity和ReadEntity方法来编写自定义序列化和反序列化代码,只有在从CloudTable检索实体或将其提交给它时才会调用 - 因此每次检索只执行一次更新操作等

    以下代码。我已经说明了一个更复杂的例子,其中我的TableEntity包含一个类,而该类又包含一个字典。

    public class MeetingLayoutEntity : TableEntity
    {
        /// <summary>
        ///  Extends TableEntity, the base class for entries in Azure CosmosDB Table tables. 
        /// </summary>
        public MeetingLayoutEntity() { }
    
        public MeetingLayoutEntity(MeetingLayout layout, string partition, string meetingId)
        {
            this.Layout = layout;
            this.PartitionKey = partition;
            this.RowKey = meetingId;
        }
    
        // Complex object which will be serialized/persisted as a JSON.
        [IgnoreProperty]
        public MeetingLayout Layout { get; set; }
    
        public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
        {
            // This line will write partition key and row key, but not Layout since it has the IgnoreProperty attribute
            var x = base.WriteEntity(operationContext);
    
            // Writing x manually as a serialized string.
            x[nameof(this.Layout)] = new EntityProperty(JsonConvert.SerializeObject(this.Layout));
            return x;
        }
    
        public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
        {
            base.ReadEntity(properties, operationContext);
            if (properties.ContainsKey(nameof(this.Layout)))
            {
                this.Layout = JsonConvert.DeserializeObject<MeetingLayout>(properties[nameof(this.Layout)].StringValue);
            }
        }
    
    }
    

    详细了解ReadEntityWriteEntity

答案 1 :(得分:5)

Azure存储表不支持将Array,List或Dictionary作为实体属性。您可以找到所有支持的属性类型here(“属性类型”部分)。

但是,您可以考虑将数组/列表/字典序列化为字符串属性,并在TableEntity类中使用[IgnoreProperty]属性声明一个属性,以将序列化字符串转换回数组/列表/字典。

public class MyEntity : TableEntity
{
    public string DicPropertyRaw { get; set; }

    [IgnoreProperty]
    public Dictionary<string, string> DicProperty
    {
        get
        {
            return Deserialize(DicPropertyRaw);
        }

        set
        {
            DicPropertyRaw = Serialize(value);
        }
    }
}

答案 2 :(得分:0)

您可以使用ObjectFlattenerRecomposer api Nuget包将任何类型的对象写入表存储: https://www.nuget.org/packages/ObjectFlattenerRecomposer/版本2.0.0还支持数组和枚举。这些属性将在写入表存储之前透明地转换为json字符串,并在从表存储中读取时反序列化为原始对象。该API还允许您将复杂对象也写入表存储。

答案 3 :(得分:0)

使用自定义属性读取/写入您的复杂类型

此解决方案具有以下优点:

  1. 您的实体对象最终仅具有针对您的复杂类型的一个属性(使用[IgnoreProperty]时不会具有两个)。
  2. 如果将ReadEntity和WriteEntity代码移至基类,则可以从您的实体中提取所有序列化代码。

此解决方案在以下网站上有详细说明: https://www.devprotocol.com/azure-table-storage-and-complex-types-stored-in-json/

Github回购: https://github.com/jtourlamain/DevProtocol.Azure.EntityPropertyConverter

如果您希望使用LINQ的解决方案: https://blog.bitscry.com/2019/04/12/adding-complex-properties-of-a-tableentity-to-azure-table-storage/

更好的方法是,使用最新的库以正确的方式进行操作,并使用内置的Flatten和ConvertBack:https://stackoverflow.com/a/35068938/1785972