如何在protobuf中只读自动生成的唯一ID字段?

问题描述

我对 protobuf 很陌生,所以请多多指教。

我注意到在 protobuf 消息类型中具有唯一标识符是很常见的,如下所示:

message Todo {
    int64 id = 1; // unique id
    string title = 2;
    string description = 3;
    google.protobuf.Timestamp reminder = 4;
}

然后可以在服务中使用消息类型来创建请求,例如

service TodoService {
  rpc Create(Todo) returns (CreateResponse) {}
}

我的预期行为是使用插入数据库时​​生成id 处理请求。但是,这意味着 id 仍然可以在请求负载中传递,但实际上会被忽略,因为 id 中的 Todo 字段仅与读取响应相关。

例如,在下面的 todo.Id 方法中根本没有引用 Create

func (s *todoServiceServer) Create(ctx context.Context,todo *v1.Todo) (*v1.CreateResponse,error) {
    
    // ... not relevant

    // insert Todo entity data
    res,err := c.ExecContext(ctx,"INSERT INTO Todo(`Title`,`Description`,`Reminder`) VALUES(?,?,?)",todo.Todo.Title,todo.Todo.Description,reminder)
    if err != nil {
        return nil,status.Error(codes.UnkNown,"Failed to insert into Todo-> "+err.Error())
    }

    // get ID of creates Todo
    id,err := res.LastInsertId()
    if err != nil {
        return nil,"Failed to retrieve id for created Todo-> "+err.Error())
    }

    return &v1.CreateResponse{
        Id:  id,},nil
}

在我看来,这在向服务发出请求时有点令人困惑,因为可以假设应该提供 id,但实际上不应该提供。由于 protobuf 中没有 readonly 字段,是否是为 Todo 提供两种不同消息类型的唯一选择,其中 id 仅出现在一种中?例如

message TodoRequest {
    // no id
    string title = 1;
    string description = 2;
    google.protobuf.Timestamp reminder = 3;
}

message Todo {
    int64 id = 1; // unique id
    string title = 2;
    string description = 3;
    google.protobuf.Timestamp reminder = 4;
}

那样 TodoRequest 仅用于创建/更新请求,而 Todo 仅用于读取响应。我唯一的问题是,仅仅为了使 id 成为“只读”而将所有其他字段定义两次似乎很乏味。

解决方法

您也可以撰写消息

syntax = "proto3";

package todo;

import "google/protobuf/timestamp.proto";

message ToDo {
    string title = 1;
    string description = 2;
    google.protobuf.Timestamp reminder = 3;
}

message ToDoEntity {
    int64 id = 1;
    ToDo todo = 2;
}

message ToDoRequest {
    ToDo todo = 1;
}