• gorm预加载及输出处理


    Gorm 预加载及输出处理(一)- 预加载应用 

     

    单条关联查询

    先创建两个关联模型:

    // 用户模型
    type User struct {
        gorm.Model
        Username string    `gorm:"type:varchar(20);not null;unique"`
        Email    string    `gorm:"type:varchar(64);not null;unique"`
        Role     string    `gorm:"type:varchar(32);not null"`
        Active   uint8     `gorm:"type:tinyint unsigned;default:1"`
        Profile  Profile   `gorm:"foreignkey:UserID;association_autoupdate:false"`
    }
    
    // 用户信息模型
    type Profile struct {
        gorm.Model
        UserID   uint      `gorm:"type:int unsigned;not null;unique"`
        Username string    `gorm:"type:varchar(20);not null;unique"`
        Nickname string    `gorm:"type:varchar(64);not null;unique"`
        Phone    string    `gorm:"type:varchar(32)"`
        Gender   uint8     `gorm:"type:tinyint unsigned;default:0"`
        Birthday time.Time `gorm:"type:datetime;default:null"`
        Sign     string    `gorm:"type:varchar(255)"`
        Avatar   string    `gorm:"type:text"`
    }
    

    直接查询单条 User 记录

    var user User
    
    DB.Debug().First(&user)
    

    这里省略 JSON 序列化输出的过程,直接看输出,类似这样:

    {
        "ID": 1,
        "CreatedAt": "2020-03-11T18:26:13+08:00",
        "UpdatedAt": "2020-03-11T18:28:41+08:00",
        "DeletedAt": null,
        "Username": "test",
        "Email": "text@demo.dev",
        "Role": "member",
        "Active": 1,
        "Profile": {
            "ID": 0,
            "CreatedAt": "001-01-01T00:00:00Z",
            "UpdatedAt": "001-01-01T00:00:00Z",
            "DeletedAt": null,
            "UserID": 0,
            "Username": "",
            "Nickname": "",
            "Phone": "",
            "Gender": 0,
            "Birthday": "0001-01-01T00:00:00Z",
            "Sign": "",
            "Avatar": ""
        }
    }
    

    可以看到,虽然有输出 Profile 字段,但是里面的字段值全为零值,也就是说直接查询 User 并不会默认把关联的 Profile 一同查询出来。

    可能有童鞋要问了,没查询 Profile 为什么还会输出空值的 Profile 字段呢?这是因为 JSON 序列化是按照模型的定义自动处理,User 模型中定义了 Profile 字段,如进行关联查询且能查到结果,那么就赋值给 Profile 字段,否则 Profile 依然序列化输出,只不过 Profile 里面的字段全都为空值。

    接下来看下如何使用关联查询获取完整的 User 数据:

    // 方式一:手动查询关联数据
    var user User
    // 第一步,查询用户
    DB.Debug().First(&user)
    // 第二步,查询关联的用户信息
    // 注意,Related 方法第二个参数为 Profile 的外键
    DB.Debug().Model(&user).Related(&user.Profile, "UserID")
    
    // 方式二:也可以使用预加载方式查询关联数据
    DB.Debug().Model(&user).Preload("Profile").First(&user)
    

    可以看到,使用预加载方式语法更简练,实际上底层还是2个查询,只不过 gorm 帮我们封装好了,现在可以获取到完整的数据,类似这样:

    {
        "ID": 1,
        "CreatedAt": "2020-03-11T18:26:13+08:00",
        "UpdatedAt": "2020-03-11T18:28:41+08:00",
        "DeletedAt": null,
        "Username": "test",
        "Email": "text@demo.dev",
        "Role": "member",
        "Active": 1,
        "Profile": {
            "ID": 1,
            "CreatedAt": "2020-03-11T18:26:13+08:00",
            "UpdatedAt": "2020-03-11T18:26:13+08:00",
            "DeletedAt": null,
            "UserID": 1,
            "Username": "test",
            "Nickname": "test",
            "Phone": "",
            "Gender": 0,
            "Birthday": "0001-01-01T00:00:00Z",
            "Sign": "",
            "Avatar": ""
        }
    }
    

    列表关联查询

    列表的关联查询和单条关联查询类似,不过手动进行列表的关联查询很繁琐,得先查出 User 列表,然后再查询一次 Profile 列表获取对应的数据,最后整合两部分数据。直接使用预加载就很简单了,代码如下:

    var users []User
    
    // 使用预加载查询
    DB.Debug().Model(&User{}).Preload("Profile").Find(&users)
    

    输出如下:

    [
        {
            "ID": 1,
            "CreatedAt": "2020-03-11T18:26:13+08:00",
            "UpdatedAt": "2020-03-11T18:28:41+08:00",
            "DeletedAt": null,
            "Username": "test",
            "Email": "text@demo.dev",
            "Role": "member",
            "Active": 1,
            "Profile": {
                "ID": 1,
                "CreatedAt": "2020-03-11T18:26:13+08:00",
                "UpdatedAt": "2020-03-11T18:26:13+08:00",
                "DeletedAt": null,
                "UserID": 1,
                "Username": "test",
                "Nickname": "test",
                "Phone": "",
                "Gender": 0,
                "Birthday": "0001-01-01T00:00:00Z",
                "Sign": "",
                "Avatar": ""
            }
        },
        ...
    ]
    

    gorm 底层使用这两条查询:

    SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL
    
    SELECT * FROM `profile`  WHERE `profile`.`deleted_at` IS
     NULL AND ((`user_id` IN (1,2,3,4,5,6)))
    

    gorm 还在内部把两条查询的数据都整合好了,使用相当方便。

    这只是一个简单的预加载应用,更多应用可参考 Gorm官方文档-预加载

    小结

    预加载在单条关联查询中提供了更简洁的语法,在列表关联查询中不仅解决了关联查询 N + 1 的问题,还自动整合了数据,方便快捷。

    到这里,一个简单的预加载查询就完成了,但是可以发现查询输出还有很多瑕疵,如:只查询 User 也会带上空值 Profile,字段名和模型定义的一样都是首字母大写,并且时间格式不友好。

    这就衍生出了几个问题:

    • 如何自定义输出结构,只输出指定字段?
    • 如何自定义字段名,并去掉空值字段?
    • 如何自定义时间格式?

    下一篇将介绍如何处理查询输出,解决上述问题。

    如发现任何问题,欢迎指正,谢谢观看!


    参考资料: Gorm官方文档

    本文出处:https://www.cnblogs.com/zhenfengxun/
    本文链接:https://www.cnblogs.com/zhenfengxun/p/12486325.html

  • 相关阅读:
    Java8 Optional使用方式
    ABAC框架-casbin
    Java数据脱敏(手机号|邮箱号|身份证号|银行卡号)
    使用OpenOffice将office文件转为pdf
    在线审批流设计
    Java 将带逗号的字符串转为List
    Java8 lambda常用操作
    Markdown合并单元格
    本博客已搬迁至rcst.xyz
    涂色(题解)
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/16200606.html
Copyright © 2020-2023  润新知