创建具有Array或List属性的TableEntity? [英] Create a TableEntity with Array or List property?

查看:110
本文介绍了创建具有Array或List属性的TableEntity?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经将一些枚举存储在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作为选择值.

解决方案

我的回答将兆兴的方法扩展为将复杂实体属性写入JSON并将其持久保存到Azure CosmosDB.

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

  1. 例如,如果要在字典DicProperty中添加或删除项目,则不会调用其设置器,因为您尚未修改字典,但已修改其内容.同样,在更复杂的用例中,如果您对序列化自定义对象或类感兴趣,则修改类的成员将不会触发设置器.当实体提交到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);
        }
    }

}

详细了解 ReadEntity ... is it possible?

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

解决方案

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.

这篇关于创建具有Array或List属性的TableEntity?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆