Create a TableEntity with Array or List property?

半腔热情 提交于 2019-12-08 19:38:04

问题


I have stored in an Azure Table some enumerations like this

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' ...

en, fr, de etc... are the language codes, and respectively the column names in the table.

What kind of TableEntity should I create in order to load it properly

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

and then use them like myFoo["fr"]... is it possible?

Say I have English GUI and I need to display a Foo select with Eune/Edoe as select values.


回答1:


My answer extends Zhaoxing's approach of writing the complex entity property to a JSON and persisting that to Azure CosmosDB.

However, serialization between a string and object in the setter causes the following issues:

  1. If, for example, you were to add or remove an item from your dictionary DicProperty, its setter would not get called since you have not modified the dictionary but have modified its contents. Similarly, in more complex use cases where you're interested in serializing custom objects or classes, modifying a member of the class will not trigger the setter. This could result in data being lost when the entity is committed to the CloudTable.
    1. If you do choose to implement something like INotifyPropertyChanged on your complex properties, either by using some form of an ObservableCollection or doing the event notification work yourself, you end up serializing and deserializing far too many times. This is also way too much code throughout your models to be useful.

Instead, I overrode TableEntity's WriteEntity and ReadEntity methods to write custom serialization and deserialization code that is only called when an entity is retrieved from the CloudTable or committed to it -- so only once for each retrieve, update operation etc.

Code below. I've illustrated a more complex example, where my TableEntity contains a class which in turn contains a dictionary.

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

}

Learn more about ReadEntity and WriteEntity.




回答2:


Azure Storage Table doesn't support Array, List or Dictionary as an entity property. You can find all the supported properties types here (section "Property Types").

However, you can consider serializing the array/list/dictionary to a string property, and declare a property with [IgnoreProperty] attribute in your TableEntity class to convert the serialized string back to array/list/dictionary.

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

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

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



回答3:


You can write any kind of object to Table storage with ObjectFlattenerRecomposer api Nuget package: https://www.nuget.org/packages/ObjectFlattenerRecomposer/ version 2.0.0 also supports arrays and enumerables. These properties will be transparently converted to json string before being written to table storage and deserialized into original object when read back from Table storage. The api also allows you to write complex objects to table storage as well.



来源:https://stackoverflow.com/questions/45517481/create-a-tableentity-with-array-or-list-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!