Azure 存储表 - 并非 TableEntity 中的所有属性都在 InsertOperation 之后存储

Posted

技术标签:

【中文标题】Azure 存储表 - 并非 TableEntity 中的所有属性都在 InsertOperation 之后存储【英文标题】:Azure Storage Tables - Not all properties from TableEntity are being stored after InsertOperation 【发布时间】:2015-04-09 09:32:37 【问题描述】:

所以问题是: 我有一个实体,它有 40 个属性(所有在代码中正确定义为“public String PropertyName get;set;”。 当我插入新实体时,大部分属性都被存储了,但其中一些没有。

代码如下:

public class PostTableEntity : TableEntity

    #region Fields
    #endregion

    #region Properties
    public Guid CreatorId  get; set; 
    public String htmlText  get; set; 
    public String SubjectIds  get; set; 
    public String QuoteString  get; set; 
    public double GeoLat  get; set; 
    public double GeoLong  get; set; 
    public String GeoPlace  get; set; 
    public Int32 TotalSmiles  get; set; 
    public DateTime DateUTC  get; set; 
    public Guid? EventId  get; set; 
    public string EventName  get; set; 
    public String ExcludedUsers  get; set; 
    public String Comment00_Text  get; set; 
    public Guid Comment00_UserId  get; set; 
    public Guid Comment00_CommentId  get; set; 
    ... //Some more props - no more than 30 in total        
    public String VeryImportantData  get; set; 
    #endregion

    #region Constructors
    public PostTableEntity()
    

    

    public PostTableEntity(String partitionKey, String rowKey, Guid creatorId, DateTime dateUTC, String htmlText)
        : base(partitionKey, rowKey)
    
        this.CreatorId = creatorId;
        this.HtmlText = htmlText;
        this.DateUTC = dateUTC;
    
    #endregion

    #region Methods
    public void SetSubjectIdsList(List<Guid> subjectIds)
    
        if (subjectIds != null)
        
            this.SubjectIds = String.Join(";", subjectIds);
        
        else
        
            this.SubjectIds = "";
        
    
    #endregion

...然后有一个派生类:

public class ImagePostTableEntity : PostTableEntity

    #region Fields
    #endregion

    #region Properties
    public String StorageAccountName  get; set; 
    public String StorageContainerName  get; set; 
    public String BlobName_Original  get; set; 
    public String BlobName_Large  get; set; 
    public String BlobName_Medium  get; set; 
    public String BlobName_Small  get; set;       
    #endregion

    #region Constructors
    public ImagePostTableEntity()
    

    

    public ImagePostTableEntity(String partitionKey, String rowKey, Guid creatorId, DateTime date, String htmlText, List<Guid> subjectIds, String storageAccountName, String storageContainerName, String blobName_Original, String blobName_Large, String blobName_Medium, String blobName_Small)
        : base(partitionKey, rowKey, creatorId, date, htmlText)
                
        this.StorageAccountName = storageAccountName;
        this.StorageContainerName = storageContainerName;            

        this.BlobName_Original = blobName_Original;
        this.BlobName_Large = blobName_Large;
        this.BlobName_Medium = blobName_Medium;
        this.BlobName_Small = blobName_Small;

        this.SetSubjectIdsList(subjectIds);
    

所以我这样称呼 InsertOperation(我觉得没什么特别的):

 ImagePostTableEntity newPost = new ImagePostTableEntity(streamId.ToString(), newPostId.ToString(), creatorId, date, htmlText, subjectIds, storageAccountName, storageContainerName, blobName_Original, blobName_Large, blobName_Medium, blobName_Small); //This construcotr calls inner method: SetSubjectIdsList(subjectIds);
            newPost.TotalComments = 0;
            newPost.VeryImportantData = "That very important string";
            TableOperation insertOperation = TableOperation.Insert(newPost);

此操作后,表存储中存在实体,但未存储某些属性。具体来说,只有“SubjectIds”和“VeryImportantData”不被存储。它们不为空,并且具有一定的价值(仔细检查;))

【问题讨论】:

实体属性中所有数据的总大小不能超过 1 MB,不确定是您的实体的问题。 msdn.microsoft.com/en-us/library/azure/dd179338.aspx 好的,新信息 ;):我删除了 azure 存储表,然后创建了一个同名:“posts”。然后它仍然不起作用,但是当我创建一个新表“posts2”时,它突然开始存储所有数据。有什么想法吗? @DSR - 感谢您的回复。存储的数据不可能超过 1 MB。有 40 个属性,每个属性最多 64 个字节 = 40*64 字节;)。那么就不是这样了。 @KrzysztofRudnicki - 40*64kb 所以你可能已经超过 1MB。您是针对模拟器还是存储帐户运行?你有任何形式的例外吗? 您能否在代码 sn-p 上方添加您实际执行插入操作的方式? 【参考方案1】:

您在保存时遇到问题或保存后缺少属性的天气。首先要注意的是TableOperation.Insert 方法本身。通过检查它的参数,很明显它接受了Microsoft.Azure.Cosmos.Table.ITableEntity 类型的参数。这意味着如果您传递任何对象,它将自动转换为该接口,当然,只要该对象来自实现该接口的类。

namespace Microsoft.WindowsAzure.Storage.Table

    public interface ITableEntity
    
        string PartitionKey  get; set; 
        string RowKey  get; set; 
        DateTimeOffset Timestamp  get; set; 
        string ETag  get; set; 

        void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext);
        IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext);
    

通过检查这个接口成员,我确定这两个属性(PartitionKey,RowKey)是必需的,应该在进入数据库之前初始化

为了通知运行时你的对象中额外的自定义成员,这个接口有一个WriteEntity 函数。此函数在内部用于返回包含对象中所有属性的集合。

幸运的是或由于最佳实践,TableEntity 类将其实现修饰为带有虚拟的WriteEntity,因此任何派生类都可以从覆盖它并添加所需的属性中受益

namespace Microsoft.WindowsAzure.Storage.Table

    public class TableEntity : ITableEntity
    
        public TableEntity();
        public TableEntity(string partitionKey, string rowKey);

        public string PartitionKey  get; set; 
        public string RowKey  get; set; 
        public DateTimeOffset Timestamp  get; set; 
        public string ETag  get; set; 

        public static TResult ConvertBack<TResult>(IDictionary<string, EntityProperty> properties, OperationContext operationContext);
        public static TResult ConvertBack<TResult>(IDictionary<string, EntityProperty> properties, EntityPropertyConverterOptions entityPropertyConverterOptions, OperationContext operationContext);
        public static IDictionary<string, EntityProperty> Flatten(object entity, OperationContext operationContext);
        public static IDictionary<string, EntityProperty> Flatten(object entity, EntityPropertyConverterOptions entityPropertyConverterOptions, OperationContext operationContext);
        public static void ReadUserObject(object entity, IDictionary<string, EntityProperty> properties, OperationContext operationContext);
        public static IDictionary<string, EntityProperty> WriteUserObject(object entity, OperationContext operationContext);
        public virtual void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext);
        public virtual IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext);
    

我为你做了一个样品。确保硬编码的值是动态的,并且会根据您应用中的某些逻辑进行计算

public class CustomClass : TableEntity

    public CustomClass()
    
        RowKey = Guid.NewGuid().ToString();
        PartitionKey = DateTime.Today.ToString("yyyy-MM");
        Timestamp = DateTime.Now;
        ETag = "*";
    

    public CustomClass(string id, string name, bool? vip) : this()
    
        Id = id;
        Name = name;
        VIP = vip;
    

    public string Id  get; set; 

    public string Name  get; set; 

    public bool? VIP  get; set; 

    public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
    
        return new Dictionary<string, EntityProperty>() 
            nameof(Id), new EntityProperty(Id) ,
            nameof(Name), new EntityProperty(Name) ,
            nameof(VIP), new EntityProperty(VIP) ,
            nameof(RowKey), new EntityProperty(RowKey) ,
            nameof(Timestamp), new EntityProperty(Timestamp) ,
            nameof(ETag), new EntityProperty(ETag) ,
            nameof(PartitionKey), new EntityProperty(PartitionKey) 
        ;
    

【讨论】:

【参考方案2】:

除了 Emily 提到的没有执行方法之外,我没有看到您为 subjectIds 设置值的代码。 Emily 提出的另一个好点是,您如何验证实体没有这些属性?

尝试使用fiddler 以确保确实正在发送某些内容。

我很确定您以前见过this guidance,但请再次检查以确保您没有遗漏任何内容。

请记住,在执行插入操作时,如果该表中已存在具有相同 PK 和 RK 的实体,则不会插入该实体。 InsertOrReplace 操作将允许您执行此操作。

【讨论】:

以上是关于Azure 存储表 - 并非 TableEntity 中的所有属性都在 InsertOperation 之后存储的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能配置 Azure 诊断以通过新的 Azure 门户使用 Azure 表存储?

使用 azure 数据工厂管道将 json 对象存储到 azure 表存储实体

Azure Functions - 使用 Azure Functions 的表存储触发器

Azure 表存储备份

Azure 函数 - Powershell 和 Azure 存储表(插入或替换)

Azure 存储表与 SQL