首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >grpc-go中模型中的空值问题

grpc-go中模型中的空值问题
EN

Stack Overflow用户
提问于 2019-03-13 11:14:48
回答 3查看 6.8K关注 0票数 4

我有两台服务器

  1. 用户服务器:处理所有用户CRUD操作
  2. Product :通过gRPC调用处理产品CRUD操作并从用户服务器获取用户信息 键入User struct { ID字符串json:"id" FirstName字符串json:"firstName" MiddleName *string json:"middleName,omitempty" LastName string json:"lastName" Email string json:"email"禁用bool json:"disabled" LastSignedInAt *time.Time json:"lastSignedInAt,omitempty" Bio *string json:"bio,omitempty" BirthDate *time.Time json:"birthDate,omitempty" } 这里有一些字段是选项,由于我使用的是cockroachDB(extended ),所以我将它们保留为指针,因此很容易扫描变量表单查询结果。

这是我的原始文件:

代码语言:javascript
复制
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;
}

现在从上面的proto文件生成的模型如下所示:“

代码语言:javascript
复制
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"`
    LastSignedInAt       string                `protobuf:"bytes,8,opt,name=lastSignedInAt,proto3" json:"lastSignedInAt,omitempty"`
    Bio                  string                `protobuf:"bytes,9,opt,name=bio,proto3" json:"bio,omitempty"`
    Birthdate            string                `protobuf:"bytes,10,opt,name=birthdate,proto3" json:"birthdate,omitempty"`
}

现在的问题是,由于我正在为可选字段使用指针,它将在没有值的情况下存储空值,但在相反的站点上,gRPC将不理解空值并抛出错误。

我尝试过google.protobuf.StringValue值作为grpc类型,如下所示

代码语言:javascript
复制
google.protobuf.StringValue lastSignedInAt = 8;

这是可行的,但问题是我必须为处理程序中的每个字段编写条件:

代码语言:javascript
复制
if lastSignedInAt != nil {
    user.LastSignedInAt = &wrappers.StringValue{Value:*lastSignedInAt}
}

解决这个问题最好的办法是什么?我应该更改数据库模型还是更改gRPC模型?

EN

回答 3

Stack Overflow用户

发布于 2019-03-20 05:00:50

正如上面的另一个答案所指出的,如果协议缓冲区消息中有可以为零的字段,那么您就需要检查它们。你对此无能为力,除非有一个实用程序包。

如果您想要缺省值超出默认协议缓冲区生成的范围,那么您必须完全按照您注意到的那样做,并检查是否为零。

不过,我确实有一些问题:

  • 为什么在第一个用户结构中为“可选”字段使用指针?如果使用普通的字符串,则在构造时使用空字符串填充,如果字段丢失,则不受json解组调用的影响。时间场也是一样。在这种情况下,字符串(空字符串)的默认值应该是无效的中间名称,而时间的默认值(0001-01: 00:00:00 +0000 UTC)是无效的时间戳(可能?)。去掉指针允许您使用缺省值。
  • 对于proto中的时间戳,您仍然可以使用字符串并检查空字符串。或者您可以使用google.protobuf.Timestamp并使用ptype来处理对非proto的转换。见https://godoc.org/github.com/golang/protobuf/ptypes#TimestampProto。在这种情况下你必须检查一下是否为零。
票数 2
EN

Stack Overflow用户

发布于 2019-03-13 11:31:25

不能将空值设置为可以使用的

代码语言:javascript
复制
oneof Examples {
    Example1 example1 = 1;
    Example2 example2 = 2;
}

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

办法2:

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

您还可以做的一件事是,不要设置零值,如果值为零,则检查条件,然后不设置任何值。

票数 1
EN

Stack Overflow用户

发布于 2019-03-18 09:33:33

如果坚持使用指针,则不建议使用point字段。

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

代码语言:javascript
复制
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
}

用法

代码语言:javascript
复制
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)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55140587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档