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 的表存储触发器