【问题标题】:Azure Table Storage: "Parameter count mismatch" storing array/list/IEnumerableAzure 表存储:“参数计数不匹配”存储数组/列表/IEnumerable
【发布时间】:2019-04-18 03:23:16
【问题描述】:

我正在尝试编写一个包含集合的简单对象,例如:

public class UserModel
{
    public string FirstName { get; set; }
    public List<string> GroupIDs { get; set; }
}

使用DynamicTableEntityFlatten 方法,我在提交实体之前设置属性,方法是将UserModel 对象作为userModel 传递,如下所示:

var entity = new DynamicTableEntity(partitionKey, rowKey);
entity.Properties = TableEntity.Flatten(userModel, new OperationContext());

这不可避免地会返回上述错误:

参数计数不匹配

据我所知,这是由于here 所述的“扁平化”方法。我尝试将我的GroupIDs 对象设置为数组、列表和 IEnumerable,但没有成功(同样的问题)。

有没有人建议在 Azure 表存储中对此类对象使用 flatten 方法提交带有字符串集合的对象?

【问题讨论】:

    标签: c# azure azure-table-storage


    【解决方案1】:

    我想分享一下我是如何解决这个问题的,因为使用DynamicTableEntity 并不清楚;至少我很容易找到。如果有其他建议,我很乐意取消标记此答案。

    选项 1:串联

    根据您的要求,如果串联结果超过 64KB 限制,这将是一个糟糕的选择。我确定还有其他方法,但是以下方法是对我有用的一种选择。首先,我更改了模型以反映字符串而不是字符串列表:

    public List<string> GroupIDs { get; set; } //instead of this
    
    public string GroupIDs { get; set; } //to this
    

    我将我的列表转换如下:

    var groupList = new List<string>{ "123", "456", "789" };
    var userObject = new UserModel(
    {
        FirstName = "Jason";
        GroupIDs = string.Join(",", groupList);
    });
    

    现在userObject.GroupIDs 属性是一个字符串,可以按照我在原始帖子中显示的那样编写。

    选项2:表设计修改

    我最终选择了第二条路线,因为通过引用原始对象上的 ID 来存储和重新水化对象更容易。我必须修改 UserModel 以删除对组的任何引用,然后我需要为其添加一个唯一 ID,如下所示:

    public class UserModel
    {
        public string FirstName { get; set; }
        public string UserId { get; set; }
    }
    

    我为原始表引用的组创建了一个表。我首先创建了一个GroupModel 对象来保存我需要引用的UserId

    public class GroupModel
    {
        public string UserId { get; set; }
        public string GroupId { get; set; }
        public string GroupName { get; set; }
    }
    

    然后我编写了一个新方法来分别处理每个对象,如下所示:

    public Interface ITableOps
    {
        Task WriteNewUser(UserModel user, List<GroupModel> groups);
    }
    
    public class TableOps : ITableOps
    {
        public async Task WriteNewUser(UserModel user, List<GroupModel>, groups)
        {
            //...assume user table connection is created
    
            var entity = new DynamicTableEntity(partitionKey, rowKey);
            entity.Properties = TableEntity.Flatten(user, new OperationContext());
            await userTable.ExecuteAsync(TableOperation.Insert(user));
    
            //...assume group table connection is created
    
            groups.ForEach(async g =>
                {
                    var groupsEntity = new DynamicTableEntity(user.UserId, Guid.NewGuid().ToString());
                    groupsEntity.Properties = TableEntity.Flatten(g, new OperationContext());
                    await groupsTable.ExecuteAsync(TableOperation.Insert(groupsEntity));
                });
        }
    

    最后,我写了一个简单的方法来从 Groups 表中读取整个 Groups 分区。

    【讨论】:

      【解决方案2】:

      是的,SDK 中的TableEntity.Flatten 不支持ICollection/IEnumerable 类型属性。但是这里的 ObjectFlatener API v2.0 支持 IEnumerable/ICollection 等属性。 https://www.nuget.org/packages/ObjectFlattenerRecomposer/

      我在 Nuget 包描述中放了一些用法示例,它与使用 TableEntity.Flatten/ConvertBack api 非常相似,但支持所有属性类型。

      【讨论】:

      • 很明显SDK中的FlattenConvertBack&lt;T&gt;就是你的代码。是否有特定原因导致 SDK 中未包含对 2.0 的更新?此外,它很难找到,因为除了可能和 API 参考之外,它主要是一个未记录的功能。
      • @AdamVincent Storage SDK 团队在我实施 2.0 并支持 IEnumerable 时已经停止接受任何进一步的贡献。表存储 SDK 功能已移植到 Cosmos DB 表客户端 SDK,但他们并未将其开源。这些 api 的一般文档与 SDK 中由 XML cmets 生成的其他 api 相同。所以不少,但我当然同意,考虑到该功能的强大程度,尤其是 2.0 nuget 版本,它并没有向开发者社区广泛宣传。
      • 真可惜,你可以用 KV 存储做很多事情,但 MS 必须推动推动 CosmosDB。感谢您的回复并将ObjectFlattenerRecomposer 提供给我们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-11
      • 1970-01-01
      相关资源
      最近更新 更多