如果子消息没有字段,如何在 protobuf 消息上分配 oneof 字段?

Posted

技术标签:

【中文标题】如果子消息没有字段,如何在 protobuf 消息上分配 oneof 字段?【英文标题】:How do I assign a oneof field on a protobuf message if the child message has no fields? 【发布时间】:2018-06-11 08:23:52 【问题描述】:

我想创建一个 BigTable DeleteFromRow 突变。 MutationDeleteFromRow 的原型如下所示:

oneof mutation 
    // Set a cell's value.
    SetCell set_cell = 1;

    // Deletes cells from a column.
    DeleteFromColumn delete_from_column = 2;

    // Deletes cells from a column family.
    DeleteFromFamily delete_from_family = 3;

    // Deletes cells from the entire row.
    DeleteFromRow delete_from_row = 4;
  


message DeleteFromRow 


在 Python 中,您不能直接实例化 DeleteFromRow 对象并将 Mutationdelete_from_row 字段设置为该对象。

所以这行不通

request = bigtable_pb2.MutateRowRequest(table_name='tablename', row_key=row_key)
mutation = request.mutations.add()
mutation.delete_from_row = data_pb2.Mutation.DeleteFromRow()

正如其他 SO 用户提出的(请参阅 this question),这会导致

AttributeError: Assignment not allowed to composite field "delete_from_row" in protocol message object.

根据protobuf docs,您应该通过设置一个子字段来设置一个oneof字段。所以应该这样创建一个DeleteFromFamily 突变:

mutation.delete_from_family.family_name = 'some_family'

但是,对于没有字段的DeleteFromRow 消息,我该如何处理?

【问题讨论】:

出于好奇,你为什么不用官方客户端? 因为它不完整。它是这个 grpc 实现之上的抽象。特别是,当我想根据一组行键或一组行键前缀读取行时,我切换到允许您在单个请求中执行此操作的底层 grpc 客户端。 知道了。 FWIW,我们现在正在开发该功能。 【参考方案1】:

你可以使用Message.SetInParent:

将此标记为存在于父级中。

当您分配子消息的字段时,这通常会自动发生,但有时您希望在保留子消息的同时将其保留为空。如果您发现自己在使用它,您可能需要重新考虑您的设计。

例子:

message Msg 
  oneof kind 
    int64 int_field = 1;
    EmptyMsg msg_field = 1;
  


message EmptyMsg 
msg = Msg()
print(msg.WhichOneof('kind'))  # None

msg.msg_field  # No-op (return EmptyMsg but don't set oneof field)
print(msg.WhichOneof('kind'))  # None

msg.msg_field.SetInParent()
print(v.WhichOneof('kind'))  # msg_field

【讨论】:

【参考方案2】:

您可以启动DeleteFromRow 对象并使用关键字参数delete_from_row 创建一个突变:

dfr = data_pb2.Mutation.DeleteFromRow()
mutation = data_pb2.Mutation(delete_from_row=dfr)

虽然您不能 addappend 对请求的重复突变字段进行这种突变(尽管在我看来这是文档所说的 here),但您可以 extend它:

request = bigtable_pb2.MutateRowRequest(table_name='tablename', row_key=row_key)
request.mutations.extend([mutation])

【讨论】:

关于该文档的链接:Repeated FieldRepeated Message Field 之间存在差异。后者没有 append 功能 - 如文档所述。

以上是关于如果子消息没有字段,如何在 protobuf 消息上分配 oneof 字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何在构建消息之前在 protobuf 中设置重复字段?

检查 protoBuf 中是不是存在消息类型

如何停止使用 protobuf3 打印错误消息“无法解析类型的消息,因为它缺少必填字段”

使用JSON模式验证protobuf消息?

Protobuf语法介绍

ProtoBuf-Net 错误消息“源数据中的无效字段:0”