在对数据进行写入、更新使用诸如Fields/Data/Scan方法时,如果给定的参数为map/struct类型,给定参数的键名/属性名称将会自动按照忽略大小写及特殊字符的方式与数据表的字段进行自动识别映射。

    这也是为什么使用GoFrame ORM执行数据库操作时会出现 SHOW FULL COLUMNS FROM `xxx` 语句的原因,该语句每张表只会执行一次,随后缓存结果到内存。

    匹配规则的示例:

    1. Map键名 字段名称 是否匹配
    2. nickname nickname match
    3. NICKNAME nickname match
    4. Nick-Name nickname match
    5. nick_name nickname match
    6. nick name nickname match
    7. NickName nickname match
    8. Nick-name nickname match
    9. nick_name nickname match
    10. nick name nickname match

    我们来看一个例子,我们实现一个查询用户基本信息的一个接口,这个用户是一个医生。

    1、我们有两张表,一张user表,大概有30个字段;一张doctor_user表,大概有80多个字段。

    2、user是用户基础表,包含用户的最基础信息;doctor_user是基于user表的业务扩展表,特定用户角色的表,与user表是一对一关系。

    3、我们有一个GRPC的接口,接口定义是这样的(为方便演示,这里做了一些简化):

    1)GetDoctorInfoRes

    1. // 查询接口返回数据结构
    2. type GetDoctorInfoRes struct {
    3. UserInfo *UserInfo `protobuf:"bytes,1,opt,name=UserInfo,proto3" json:"UserInfo,omitempty"`
    4. DoctorInfo *DoctorInfo `protobuf:"bytes,2,opt,name=DoctorInfo,proto3" json:"DoctorInfo,omitempty"`
    5. XXX_NoUnkeyedLiteral struct{} `json:"-"`
    6. XXX_unrecognized []byte `json:"-"`
    7. XXX_sizecache int32 `json:"-"`
    8. }

    2)UserInfo

    1. // 用户基础信息
    2. type UserInfo struct {
    3. Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
    4. Avatar string `protobuf:"bytes,2,opt,name=avatar,proto3" json:"avatar,omitempty"`
    5. Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
    6. Sex int32 `protobuf:"varint,4,opt,name=sex,proto3" json:"sex,omitempty"`
    7. XXX_NoUnkeyedLiteral struct{} `json:"-"`
    8. XXX_unrecognized []byte `json:"-"`
    9. XXX_sizecache int32 `json:"-"`
    10. }

    3)DoctorInfo

    1. // 医生信息
    2. type DoctorInfo struct {
    3. Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
    4. Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
    5. Hospital string `protobuf:"bytes,4,opt,name=hospital,proto3" json:"hospital,omitempty"`
    6. Section string `protobuf:"bytes,6,opt,name=section,proto3" json:"section,omitempty"`
    7. Title string `protobuf:"bytes,8,opt,name=title,proto3" json:"title,omitempty"`
    8. XXX_NoUnkeyedLiteral struct{} `json:"-"`
    9. XXX_unrecognized []byte `json:"-"`
    10. XXX_sizecache int32 `json:"-"`
    11. }

    4、查询接口实现代码

    1. // 查询医生信息
    2. func (s *Service) GetDoctorInfo(ctx context.Context, req *pb.GetDoctorInfoReq) (res *pb.GetDoctorInfoRes, err error) {
    3. // Protobuf返回数据结构
    4. res = &pb.GetDoctorInfoRes{}
    5. // 查询医生信息
    6. // SELECT `id`,`avatar`,`name`,`sex` FROM `user` WHERE `user_id`=xxx
    7. err = dao.PrimaryDoctorUser.
    8. Ctx(ctx).
    9. Fields(res.DoctorInfo).
    10. Where(dao.PrimaryDoctorUser.Columns.UserId, req.Id).
    11. Scan(&res.DoctorInfo)
    12. if err != nil {
    13. return
    14. }
    15. // 查询基础用户信息
    16. // SELECT `id`,`name`,`hospital`,`section`,`title` FROM `doctor_user` WHERE `id`=xxx
    17. err = dao.PrimaryUser.
    18. Ctx(ctx).
    19. Fields(res.DoctorInfo).
    20. Where(dao.PrimaryUser.Columns.Id, req.Id).
    21. Scan(&res.UserInfo)
    22. return res, err
    23. }

    当我们调用GetDoctorInfo执行查询时,将会向数据库发起两条SQL查询,例如:

    1. SELECT `id`,`avatar`,`name`,`sex` FROM `user` WHERE `user_id`=1
    2. SELECT `id`,`name`,`hospital`,`section`,`title` FROM `doctor_user` WHERE `id`=1

    可以看到:

    • 使用Fields方法时,参数类型为struct或者*structORM将会自动将struct的属性名称与数据表的字段名称做自动映射匹配,当映射匹配成功时只会查询特定字段数据,而不存在的属性字段将会被自动过滤。
    • 使用Scan方法时(也可以用Struct/Structs),参数类型为*struct或者**struct,查询结果将会自动与struct的属性做自动映射匹配,当映射匹配成功时会自动做转换赋值,否则不会对参数的属性做任何处理。