为了账号安全,请及时绑定邮箱和手机立即绑定

grpc-go 模型中的空值问题

grpc-go 模型中的空值问题

Go
绝地无双 2023-06-12 17:25:46
我有两台服务器用户服务器:处理所有用户增删改查操作产品服务器:处理产品 CRUD 操作并通过 gRPC 调用从用户服务器获取用户信息type User struct {    ID string `json:"id"`    FirstName      string     `json:"firstName"`    MiddleName     *string    `json:"middleName,omitempty"`    LastName       string     `json:"lastName"`    Email          string     `json:"email"`    Disabled       bool       `json:"disabled"`    LastSignedInAt *time.Time `json:"lastSignedInAt,omitempty"`    Bio            *string    `json:"bio,omitempty"`    BirthDate      *time.Time `json:"birthDate,omitempty"`}这里有些字段是可选的,因为我使用的是 cockroachDB(扩展的 postgreSQL),所以我将它们保存为指针,以便扫描可变形式的查询结果很容易。这是我的原型文件:message User {    int64 id = 1;    string firstName = 2;    string lastName = 3;    string email = 5;    bool disabled = 6;    string lastSignedInAt = 8;    string bio = 9;    string birthdate = 10;    string profession = 14;}现在从上面的原型文件生成的模型是这样的:“type User struct {    Id                   int64                 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`    FirstName            string                `protobuf:"bytes,2,opt,name=firstName,proto3" json:"firstName,omitempty"`    LastName             string                `protobuf:"bytes,3,opt,name=lastName,proto3" json:"lastName,omitempty"`    Email                string                `protobuf:"bytes,4,opt,name=email,json=email,proto3" json:"email,omitempty"`    Disabled             bool                  `protobuf:"varint,6,opt,name=disabled,proto3" json:"disabled,omitempty"`}现在的问题是,因为我正在为可选字段使用指针,它会在没有值的情况下存储空值,但在对面的站点上,gRPC 不会理解空值并抛出错误。我试过google.protobuf.StringValue像这样将值作为 grpc 类型google.protobuf.StringValue lastSignedInAt = 8;这可行,但问题是我必须为处理程序中的每个字段编写条件:if lastSignedInAt != nil {    user.LastSignedInAt = &wrappers.StringValue{Value:*lastSignedInAt}}解决这个问题的最佳方法是什么?我应该更改数据库模型还是 gRPC 模型中的任何更改?
查看完整描述

3 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

如果协议缓冲区消息的字段可以为 nil,则由您检查它们。对此你无能为力,除非有一个实用程序包可以做到这一点。

如果您希望默认值高于和超出协议缓冲区生成的默认值,则必须完全按照您的记录进行操作并检查是否为 nil。

我确实有一些问题:

  • 为什么对第一个用户结构中的“可选”字段使用指针?如果您使用普通的旧字符串,它们将在构造时填充空字符串,并且如果该字段丢失,则不会被 json unmarshal 调用触及。时间字段也一样。在这种情况下,字符串的默认值(空字符串)应该是无效的中间名,时间的默认值 (0001-01-01 00:00:00 +0000 UTC) 是无效的时间戳(可能?)。摆脱指针允许您使用默认值。

  • 对于原型结构中的时间戳,您仍然可以使用字符串并检查空字符串。或者您可以使用 google.protobuf.Timestamp 并使用 ptypes 来处理与非原型结构之间的转换。


查看完整回答
反对 回复 2023-06-12
?
大话西游666

TA贡献1817条经验 获得超14个赞

grpc 不推荐使用点域,如果你坚持使用指针


一种方法是使用反射来转换它


func ToGrpcData(in, out interface{}) error {

    inVal := reflect.ValueOf(in)

    if inVal.Kind() == reflect.Ptr {

        inVal = inVal.Elem()

    }

    inTyp := inVal.Type()


    outVal := reflect.ValueOf(out)

    if outVal.Kind() != reflect.Ptr {

        return errors.New("out data must be point value")

    }


    outVal = outVal.Elem()

    outTyp := outVal.Type()


    strWrapperType := reflect.TypeOf(wrappers.StringValue{})

    // range all 'in' fields

    for i := 0; i < inVal.NumField(); i++ {

        fTyp := inTyp.Field(i)

        fVal := inVal.Field(i)

        if fTyp.Type.Kind() == reflect.Ptr {

            switch fTyp.Type.Elem().Kind() {

            case reflect.String: // only implement string in this test

                oFTyp, ok := outTyp.FieldByName(fTyp.Name)

                if ok == false {

                    return errors.New("not match field in out value")

                }

                if oFTyp.Type.Elem() != strWrapperType {

                    return errors.New("not match field in out value")

                }

                if fVal.IsNil() == false {

                    outVal.FieldByName(fTyp.Name).Set(

                        reflect.ValueOf(&wrappers.StringValue{

                            Value: fVal.Elem().String(),

                        }),

                    )

                }

            }

        } else {

            outVal.FieldByName(fTyp.Name).Set(fVal)

        }

    }

    return nil

}

用法


type User struct {

    Name  string

    Value *string

}

type ServerUser struct {

    Name  string

    Value *wrappers.StringValue

}

usValue := "123"

u1 := User{

    Name:  "tom",

    Value: &usValue,

}

u2 := ServerUser{}

err := ToGrpcData(&u1, &u2)

// error process ...

fmt.Println(u2)


查看完整回答
反对 回复 2023-06-12
?
LEATH

TA贡献1936条经验 获得超6个赞

你不能设置空值而不是你可以使用


oneof Examples {

    Example1 example1 = 1;

    Example2 example2 = 2;

}

当你使用 oneof 时,你必须只设置一个值,你可以设置 example1 或 example2 你不能同时使用两者。与设置 nil 值相比,这将解决您的问题。


方法二:


默认情况下,gRPC 的所有变量都具有初始值 ex: string: ""


您还可以做的一件事是不要设置 nil 值检查条件,如果您的值为 nil,则什么都不设置。


查看完整回答
反对 回复 2023-06-12
  • 3 回答
  • 0 关注
  • 214 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信