You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GORM操作MSSQL查询获取的UUID值与数据库存储值不一致

问题

模型定义

type Invoice struct {
    ID                uint           `gorm:"primarykey" json:"-"`
    UID               uuid.UUID      `gorm:"type:UNIQUEIDENTIFIER;uniqueIndex:idx_UniqueID" json:"id"`
}

数据库中存储的字段值如下图所示:
数据库存储的UID值

但通过GORM从数据库检索数据时,获取到的UID值与数据库内存储的原值存在差异,查询返回值如下图:
GORM查询返回的UID值

请问该问题是否是模型定义环节存在错误导致?相关接口处理handler代码如下:

func GetInvoices(c *fiber.Ctx) error {
    invoices := []responses.Invoice{}
    var invoicesCount int64

    page, pageSize, searchString, orderBy := handles.Pages(c)
    switch orderBy {
    case "customer_name":
        orderBy = "CustomerName"
    case "currency_id":
        orderBy = "ForeignCurrenycID"
    default:
        orderBy = "ID"
    }

    if err := database.DB.Model(&models.Invoice{}).Select("ID").Where("InvNumber like ? or CustomerName like ? or Tax_Number like ? or Registration like ? or Description like ?", searchString, searchString, searchString, searchString, searchString).Count(&invoicesCount).Error; err != nil {
        logs.ErrorLogger.Println(err.Error())
        return c.Status(400).JSON(fiber.Map{"msg": err.Error()})
    }

    if err := database.DB.Scopes(handles.Paginate(c)).Order(orderBy).Find(&invoices).Where("InvNumber like ? or CustomerName like ? or Tax_Number like ? or Registration like ? or Description like ?", searchString, searchString, searchString, searchString, searchString).Error; err != nil {
        logs.ErrorLogger.Println(err.Error())
        return c.Status(400).JSON(fiber.Map{"msg": err.Error()})
    }
    for _, inv := range invoices{
        fmt.Println(inv.UID)
    }
    totalPages := math.Ceil(float64(invoicesCount) / float64(pageSize))

    return c.Status(200).JSON(fiber.Map{"page": page, "pageSize": pageSize, "totalPages": totalPages, "totalItems": invoicesCount, "data": &invoices})
}

回答

该问题不是模型定义环节错误导致,核心问题出在GORM查询逻辑的写法错误,直接触发了UID字段读取值与库内存储不一致的现象。

具体问题点

  • GORM链式调用顺序错误,过滤条件完全未生效
    现有数据查询逻辑写为.Order(orderBy).Find(&invoices).Where(...),GORM中Find属于终结执行方法,调用后会立刻生成SQL并执行查询,后面拼接的Where过滤条件根本不会被加入到本次查询的SQL中,相当于直接做了全表查询,返回的结果集和预期带过滤条件的结果完全不匹配,很容易出现记录对不上、UID不符的情况。
    额外提一句,代码中currency_id映射的排序字段写为ForeignCurrenycID存在拼写错误,正确拼写应为ForeignCurrencyID,触发该排序规则时会报列不存在的SQL错误,可以一并修正。
  • 查询未绑定正确模型,存在字段扫描错位风险
    执行数据查询时,既没有调用Model(&models.Invoice{})指定关联的模型,也没有显式调用Table()指定表名,GORM会直接根据传入的[]responses.Invoice结构体推断表结构与字段映射关系。如果responses.Invoice的字段顺序、字段标签、字段类型和实际表结构、models.Invoice定义不完全对齐,就会出现数据库返回的字段值被扫描到错误结构体字段上的问题,直接表现就是UID这类字段读到的值和库内存储完全不符。
    另外现有Count查询中写的.Select("ID")属于冗余写法,虽然不会影响计数结果,但没有实际存在的必要。

修复方案

  1. 调整GORM链式调用顺序,所有过滤、排序、分页条件必须放在Find这类终结方法之前
  2. 查询时统一绑定models.Invoice作为模型,避免表结构、字段映射错位,查询完成后手动将模型结构转换为接口响应需要的responses.Invoice结构
  3. 公共查询条件可以提前拼装复用,避免重复编写相同的Where逻辑

修正后的核心查询代码如下:

func GetInvoices(c *fiber.Ctx) error {
    page, pageSize, searchString, orderBy := handles.Pages(c)
    switch orderBy {
    case "customer_name":
        orderBy = "CustomerName"
    case "currency_id":
        // 修正原有拼写错误
        orderBy = "ForeignCurrencyID"
    default:
        orderBy = "ID"
    }

    invoices := []responses.Invoice{}
    var invoicesCount int64

    // 提前拼装公共查询条件,复用逻辑,减少重复代码
    baseQuery := database.DB.Model(&models.Invoice{}).Where(
        "InvNumber like ? or CustomerName like ? or Tax_Number like ? or Registration like ? or Description like ?",
        searchString, searchString, searchString, searchString, searchString,
    )

    // 计数查询复用基础条件,去掉冗余的Select("ID")
    if err := baseQuery.Count(&invoicesCount).Error; err != nil {
        logs.ErrorLogger.Println(err.Error())
        return c.Status(400).JSON(fiber.Map{"msg": err.Error()})
    }

    // 查询数据:所有条件放在Find之前,先查询模型结构,保证字段映射正确
    var invoiceModels []models.Invoice
    if err := baseQuery.Scopes(handles.Paginate(c)).Order(orderBy).Find(&invoiceModels).Error; err != nil {
        logs.ErrorLogger.Println(err.Error())
        return c.Status(400).JSON(fiber.Map{"msg": err.Error()})
    }

    // 手动完成模型到响应结构的转换,彻底避免结构体自动映射带来的错位问题
    for _, inv := range invoiceModels {
        fmt.Println(inv.UID) // 此处打印的UID会与数据库存储值完全一致
        invoices = append(invoices, responses.Invoice{
            UID: inv.UID,
            // 按照responses.Invoice的实际结构补充其余字段赋值
        })
    }

    totalPages := math.Ceil(float64(invoicesCount) / float64(pageSize))
    return c.Status(200).JSON(fiber.Map{
        "page": page,
        "pageSize": pageSize,
        "totalPages": totalPages,
        "totalItems": invoicesCount,
        "data": &invoices,
    })
}

补充说明:如果修正上述逻辑后仍存在UUID值异常,请确认项目使用的uuid.UUID类型已正确实现sql.Scanner和driver.Valuer接口,主流的github.com/google/uuid库v1.1.0及以上版本已原生支持SQL Server的UNIQUEIDENTIFIER类型读写,不需要额外调整模型定义的标签配置。

内容的提问来源于stack exchange,提问作者Luqman Jr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:06:09