grpc-go 模型中的空值问题

我有两台服务器


用户服务器:处理所有用户增删改查操作

产品服务器:处理产品 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 模型中的任何更改?


绝地无双
浏览 215回答 3
3回答

婷婷同学_

如果协议缓冲区消息的字段可以为 nil,则由您检查它们。对此你无能为力,除非有一个实用程序包可以做到这一点。如果您希望默认值高于和超出协议缓冲区生成的默认值,则必须完全按照您的记录进行操作并检查是否为 nil。我确实有一些问题:为什么对第一个用户结构中的“可选”字段使用指针?如果您使用普通的旧字符串,它们将在构造时填充空字符串,并且如果该字段丢失,则不会被 json unmarshal 调用触及。时间字段也一样。在这种情况下,字符串的默认值(空字符串)应该是无效的中间名,时间的默认值 (0001-01-01 00:00:00 +0000 UTC) 是无效的时间戳(可能?)。摆脱指针允许您使用默认值。对于原型结构中的时间戳,您仍然可以使用字符串并检查空字符串。或者您可以使用 google.protobuf.Timestamp 并使用 ptypes 来处理与非原型结构之间的转换。

大话西游666

grpc 不推荐使用点域,如果你坚持使用指针一种方法是使用反射来转换它func ToGrpcData(in, out interface{}) error {&nbsp; &nbsp; inVal := reflect.ValueOf(in)&nbsp; &nbsp; if inVal.Kind() == reflect.Ptr {&nbsp; &nbsp; &nbsp; &nbsp; inVal = inVal.Elem()&nbsp; &nbsp; }&nbsp; &nbsp; inTyp := inVal.Type()&nbsp; &nbsp; outVal := reflect.ValueOf(out)&nbsp; &nbsp; if outVal.Kind() != reflect.Ptr {&nbsp; &nbsp; &nbsp; &nbsp; return errors.New("out data must be point value")&nbsp; &nbsp; }&nbsp; &nbsp; outVal = outVal.Elem()&nbsp; &nbsp; outTyp := outVal.Type()&nbsp; &nbsp; strWrapperType := reflect.TypeOf(wrappers.StringValue{})&nbsp; &nbsp; // range all 'in' fields&nbsp; &nbsp; for i := 0; i < inVal.NumField(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; fTyp := inTyp.Field(i)&nbsp; &nbsp; &nbsp; &nbsp; fVal := inVal.Field(i)&nbsp; &nbsp; &nbsp; &nbsp; if fTyp.Type.Kind() == reflect.Ptr {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch fTyp.Type.Elem().Kind() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case reflect.String: // only implement string in this test&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oFTyp, ok := outTyp.FieldByName(fTyp.Name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ok == false {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return errors.New("not match field in out value")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if oFTyp.Type.Elem() != strWrapperType {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return errors.New("not match field in out value")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if fVal.IsNil() == false {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outVal.FieldByName(fTyp.Name).Set(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reflect.ValueOf(&wrappers.StringValue{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Value: fVal.Elem().String(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outVal.FieldByName(fTyp.Name).Set(fVal)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return nil}用法type User struct {&nbsp; &nbsp; Name&nbsp; string&nbsp; &nbsp; Value *string}type ServerUser struct {&nbsp; &nbsp; Name&nbsp; string&nbsp; &nbsp; Value *wrappers.StringValue}usValue := "123"u1 := User{&nbsp; &nbsp; Name:&nbsp; "tom",&nbsp; &nbsp; Value: &usValue,}u2 := ServerUser{}err := ToGrpcData(&u1, &u2)// error process ...fmt.Println(u2)

LEATH

你不能设置空值而不是你可以使用oneof Examples {&nbsp; &nbsp; Example1 example1 = 1;&nbsp; &nbsp; Example2 example2 = 2;}当你使用 oneof 时,你必须只设置一个值,你可以设置 example1 或 example2 你不能同时使用两者。与设置 nil 值相比,这将解决您的问题。方法二:默认情况下,gRPC 的所有变量都具有初始值 ex: string: ""您还可以做的一件事是不要设置 nil 值检查条件,如果您的值为 nil,则什么都不设置。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go