[gogf/gf]orm中的ScanList功能,在复杂情况下会失效

2024-07-09 783 views
8

go1.15

gf master

orm中的ScanList功能,在复杂情况下会失效

示例代码:


// 多个用户,每个用户有多本书,每本书有一个出版社信息

//出版社
type PublishingHouse struct {
    Id int `json:"id"`
}
type Book struct {
    Id              int             `json:"id"`
    Name            string          `json:"name"`
    UserId          int             `json:"user_id"`
    CreateAt        *gtime.Time     `json:"created_at"`
    PublishingHouse PublishingHouse `json:"publishing_house"` //如果去掉这一属性能赋值成功,但实际在多层嵌套时,中间一些层,基本上都会是这样的形式
}

type User struct {
    Id       int         `json:"id"`
    Nickname string      `json:"nickname"`
    CreateAt *gtime.Time `json:"created_at"`
}

type UserEntity struct {
    User
    Books []Book `json:"books"`
}

func createTableUser() string {
    db := g.Database()
    db.SetDebug(true)
    tableName := "users_" + gconv.String(gtime.Now().Nanosecond())
    if _, err := db.Exec(fmt.Sprintf(`
        CREATE TABLE %s (
            id          int(10) unsigned NOT NULL AUTO_INCREMENT,
            nickname    varchar(45) NULL,
            created_at    datetime NULL,
            PRIMARY KEY (id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
        `, tableName,
    )); err != nil {
        gtest.Fatal(err)
    }
    return tableName
}
func createTableBook() string {
    db := g.Database()
    db.SetDebug(true)
    tableName := "books_" + gconv.String(gtime.Now().Nanosecond())
    if _, err := db.Exec(fmt.Sprintf(`
        CREATE TABLE %s (
            id          int(10) unsigned NOT NULL AUTO_INCREMENT,
            name    varchar(45) NULL,
            user_id    int(10) NULL,
            created_at    datetime NULL,
            PRIMARY KEY (id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
        `, tableName,
    )); err != nil {
        gtest.Fatal(err)
    }
    return tableName
}

func fillData(tableName1 string, tableName2 string) {
    db := g.Database()

    for i := 0; i < 5; i++ {
        user := &User{
            Nickname: "张" + gconv.String(i),
        }
        if rs, err := db.Table(tableName1).Save(user); err == nil {
            rsLid, _ := rs.LastInsertId()
            for j := 0; j < 3; j++ {
                book := &Book{
                    Name:   "书" + gconv.String(j),
                    UserId: gconv.Int(rsLid),
                }
                db.Table(tableName2).Save(book)
            }

        }
    }
}

// 删除表
func dropTable(table []string) {
    db := g.Database()
    for _, v := range table {
        if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", v)); err != nil {
            gtest.Error(err)
        }
    }

}

func TestScanList(t *testing.T) {
    userName := createTableUser()
    bookName := createTableBook()
    fillData(userName, bookName)
    db := g.Database()
    var entity []UserEntity

    _ = db.Table(userName).Structs(&entity)

    _ = db.Table(bookName).Where("user_id", gdb.ListItemValuesUnique(&entity, "Id")).
        ScanList(&entity, "Books", "User", "user_id:Id")
    dropTable([]string{userName, bookName})

    for _, v := range entity {
        if v.Books == nil {
            g.Dump("err!")
        } else {
            g.Dump("ok!")
        }
    }
    g.Dump("done!")

}

回答

1

@jroam 感谢反馈,你这个代码有点复杂,我先捋捋

8

其它代码都是构建数据表和填充一些数据,并申明一些必要的结构体。 主要是查询结果那里.

7

@jroam 我还花了不少时间,但你的示例走不通。你可以再简化一下,不需要走数据库,直接走gutil.ScanList方法。给一个最小可运行的示例。

5

最简化如下:

//出版社
type PublishingHouse struct {
    Id int `json:"id"`
}

type Book struct {
    Id              int             `json:"id"`
    Name            string          `json:"name"`
    UserId          int             `json:"user_id"`
    CreateAt        *gtime.Time     `json:"created_at"`
    PublishingHouse PublishingHouse `json:"publishing_house"` //如果去掉这一属性,用ScanList能赋值成功
}
3

@jroam 这个是你的代码问题,我改了下你的代码,你试试看下面的代码。问题解决了必须给我个红包才行。

package main

import (
    "fmt"
    "github.com/gogf/gf/database/gdb"
    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/os/gtime"
    "github.com/gogf/gf/test/gtest"
    "github.com/gogf/gf/util/gconv"
    "testing"
)

// 多个用户,每个用户有多本书,每本书有一个出版社信息

//出版社
type PublishingHouse struct {
    Id int `json:"id"`
}
type Book struct {
    Id              int             `json:"id"`
    Name            string          `json:"name"`
    UserId          int             `json:"user_id"`
    CreateAt        *gtime.Time     `json:"created_at"`
    PublishingHouse PublishingHouse `json:"publishing_house"` //如果去掉这一属性能赋值成功,但实际在多层嵌套时,中间一些层,基本上都会是这样的形式
}

type User struct {
    Id       int         `json:"id"`
    Nickname string      `json:"nickname"`
    CreateAt *gtime.Time `json:"created_at"`
}

type UserEntity struct {
    User
    Books []Book `json:"books"`
}

func createTableUser() string {
    db := g.Database()
    db.SetDebug(true)
    tableName := "users_" + gconv.String(gtime.Now().Nanosecond())
    if _, err := db.Exec(fmt.Sprintf(`
        CREATE TABLE %s (
            id          int(10) unsigned NOT NULL AUTO_INCREMENT,
            nickname    varchar(45) NULL,
            created_at    datetime NULL,
            PRIMARY KEY (id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
        `, tableName,
    )); err != nil {
        gtest.Fatal(err)
    }
    return tableName
}
func createTableBook() string {
    db := g.Database()
    db.SetDebug(true)
    tableName := "books_" + gconv.String(gtime.Now().Nanosecond())
    if _, err := db.Exec(fmt.Sprintf(`
        CREATE TABLE %s (
            id          int(10) unsigned NOT NULL AUTO_INCREMENT,
            name    varchar(45) NULL,
            user_id    int(10) NULL,
            created_at    datetime NULL,
            PRIMARY KEY (id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
        `, tableName,
    )); err != nil {
        gtest.Fatal(err)
    }
    return tableName
}

func fillData(tableName1 string, tableName2 string) {
    db := g.Database()

    for i := 0; i < 5; i++ {
        user := &User{
            Nickname: "张" + gconv.String(i),
        }
        if rs, err := db.Table(tableName1).Save(user); err == nil {
            rsLid, _ := rs.LastInsertId()
            for j := 0; j < 3; j++ {
                book := &Book{
                    Name:   "书" + gconv.String(j),
                    UserId: gconv.Int(rsLid),
                }
                _, err := db.Table(tableName2).Filter().Save(book)
                if err != nil {
                    panic(err)
                }
            }
        } else {
            panic(err)
        }
    }
}

// 删除表
func dropTable(table []string) {
    db := g.Database()
    for _, v := range table {
        if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", v)); err != nil {
            gtest.Error(err)
        }
    }

}

func TestScanList(t *testing.T) {
    userName := createTableUser()
    bookName := createTableBook()
    fillData(userName, bookName)
    db := g.Database()
    var entity []UserEntity

    err := db.Table(userName).Structs(&entity)
    gtest.Assert(err, nil)
    err = db.Table(bookName).Where("user_id", gdb.ListItemValuesUnique(&entity, "Id")).
        ScanList(&entity, "Books", "User", "user_id:Id")
    dropTable([]string{userName, bookName})
    gtest.Assert(err, nil)
    for _, v := range entity {
        if v.Books == nil {
            g.Dump("err!")
        } else {
            g.Dump("ok!")
        }
    }
    g.Dump("done!")

}
7

哈哈,要得。