Azure存储和条件替换/合并

inf*_*ity 5 c# upsert insert-update azure azure-table-storage

在Azure表存储的批量保存操作中,是否有一种有效的方法来替换实体上的某些属性(如果已存在);但是更新新实体的所有属性吗?

这是我正在谈论的场景。

我有一个名为Order的实体

public class Order : TableEntity
{
    public Order(String department, string orderId)
    {
        this.PartitionKey = department;
        this.RowKey = orderId;
    }

    public DateTime CreatedOn {get; set;}
    public String CreatedBy {get; set;}

    public DateTime UpdatedOn {get; set;}
    public String UpdatedBy {get; set;}

    //Class contains other properties which could add up to 1MB
}
Run Code Online (Sandbox Code Playgroud)

情境

  1. Azure表存储具有带有RowKeys [0..100]的订单实体
  2. 我的API收到带有RowKeys [50..150]的订单的增补请求。
  3. 在单批交易中,我需要更新订单[50-100]上的某些属性,并在天蓝色时创建新的订单实体[101-150]。
  4. 注意:在现有订单[50..100]上,除CreatedOn,CreatedBy,PartitionKey和RowKey之外的所有属性都需要更新。

我可以在不读取表存储中内容的情况下一步完成此操作吗?

这是一种实现方法(非常粗糙的伪代码)

function Upsert(Dictionary<String, Order> ordersInput)
{
    //1. Read existing ordersInput from database
    var existingOrders = Retrieve(ordersInput.Values);

    //2. Update 'ordersInput' with existing data
    foreach(var existingOrder in existingOrders)
    {
        if(ordersInput.ContainsKey(existingOrder.RowKey)
        {
            ordersInput[existingOrder.RowKey].CreatedOn = existingOrder.CreatedOn;
            ordersInput[existingOrder.RowKey].CreatedBy = existingOrder.CreatedBy;
        }
    }

    //Save all merged orders to Azure
    SaveToAzure(existingOrders);
}
Run Code Online (Sandbox Code Playgroud)

我使用上述方法遇到的问题是,每个订单实体的大小均为1 MB,读取所有实体会使API保存操作陷入困境。

是否有一种更有效的方法可以完全在azure上执行条件合并?

我也在考虑通过以下方式进行批量插入

  1. 对所有订单进行批量插入
  2. 如果上一步失败并显示“ 指定的实体已存在 ”,则创建两个新批次(一个具有现有行键,另一个具有新行键)并分别处理每个批次

(以上方法听起来很hacky,我认为这可能会导致大量并发问题)

Gau*_*tri 5

Azure表存储本身Upsert通过InsertOrReplaceInsertOrMerge功能支持操作。InsertOrReplace如果存在,将使用新实体完全替换一个实体,否则将创建一个新实体。InsertOrMerge如果存在具有相同PartitionKey / RowKey的实体,则它将更改新实体中存在的现有实体的属性,否则它将创建一个新实体。

更新

这是另一种方法。您可以做的几件事:

  1. 查询投影:查询投影仅允许您获取实体的某些属性。因此,当您获取现有实体时,只需获取PartitionKey和,RowKey这样您就可以确定一个实体是否已经存在。这将大大减少响应有效载荷。
  2. 可为空的字段:由于您不希望为现有实体更新CreatedOnCreatedBy字段,因此需要使它们特别为可为空CreatedOn

基于此,您首先要获取现有实体。检索操作将仅返回PartitionKeyRowKey(使用查询投影技术)。然后,您将遍历ordersInput并查看该实体是否存在。如果实体存在,那么您将设置CreatedOnCreatedBy作为null和标记实体是Merged。如果该实体不存在,则将设置所有属性并将该实体标记为Inserted。然后,您将此批处理请求发送到表服务。

  • 我确实探索了 InsertOrMerge 操作,但它不适用于我提到的场景。如果实体已经在 Azure 上,有没有办法告诉 InsertOrMerge 跳过更新特定属性(例如,如果实体已经在 Azure 上,则不应覆盖由字段创建,即使传递新值) (2认同)