【问题标题】:Create a TableEntity with Array or List property?使用 Array 或 List 属性创建 TableEntity?
【发布时间】:2018-01-13 00:32:41
【问题描述】:

我在 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 作为选择值。

【问题讨论】:

    标签: azure-table-storage azure-tablequery


    【解决方案1】:

    我的回答扩展了肇兴将复杂实体属性写入 JSON 并将其持久化到 Azure CosmosDB 的方法。

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

    1. 例如,如果您要在字典 DicProperty 中添加或删除项目,则不会调用其设置器,因为您尚未修改字典但已修改其内容。同样,在您对序列化自定义对象或类感兴趣的更复杂用例中,修改类的成员不会触发 setter。当实体提交到 CloudTable 时,这可能会导致数据丢失。
      1. 如果您确实选择在复杂属性上实现类似 INotifyPropertyChanged 的​​功能,无论是通过使用某种形式的 ObservableCollection 还是自己进行事件通知工作,您最终都会序列化和反序列化太多次。这也是整个模型中的太多代码,没有用处。

    相反,我重写了 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

    【讨论】:

      【解决方案2】:

      Azure 存储表不支持将数组、列表或字典作为实体属性。您可以找到所有受支持的属性类型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);
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

          此方案具有以下优点:

          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

          【讨论】:

            猜你喜欢
            • 2011-05-26
            • 1970-01-01
            • 2018-08-03
            • 1970-01-01
            • 1970-01-01
            • 2012-10-27
            • 2018-08-15
            • 2022-10-14
            • 2021-11-14
            相关资源
            最近更新 更多