G

[Golang] GORM框架 三种特殊查询

RoLingG 2024-10-10

Find to map

GORM 提供了灵活的数据查询,允许将结果扫描进(scanned into)map[string]interface{} or []map[string]interface{},这对动态数据结构非常有用。

当使用 Find To Map时,一定要在你的查询中包含 Model 或者 Table ,以此来显式地指定表名。 这能确保 GORM 正确的理解哪个表要被查询。

// 扫描第一个结果到 map with Model 中
result := map[string]interface{}{}
db.Model(&User{}).First(&result, "id = ?", 1)
// SQL: SELECT * FROM `users` WHERE id = 1 LIMIT 1

// 扫描多个结果到部分 maps with Table 中
var results []map[string]interface{}
db.Table("users").Find(&results)
// SQL: SELECT * FROM `users`

FirstOrInit

GORM 的 FirstOrInit 方法用于获取与特定条件匹配的第一条记录,如果没有成功获取,就初始化一个新实例。 这个方法与结构和map条件兼容,并且在使用 AttrsAssign 方法时有着更多的灵活性。

// 如果没找到 name 为 "non_existing" 的 User,就初始化一个新的 User
var user User
db.FirstOrInit(&user, User{Name: "non_existing"})
// user -> User{Name: "non_existing"} if not found

// 检索名为 “jinzhu” 的 User
db.Where(User{Name: "jinzhu"}).FirstOrInit(&user)
// user -> User{ID: 111, Name: "Jinzhu", Age: 18} if found

// 使用 map 来指定搜索条件
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
// user -> User{ID: 111, Name: "Jinzhu", Age: 18} if found

使用 Attrs 进行初始化

当记录未找到,你可以使用 Attrs 来初始化一个有着额外属性的结构体。 这些属性包含在新结构中,但不在 SQL 查询中使用。

// 如果没找到对应条件的 User,会根据所给条件和额外属性初始化 User
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// SQL: SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
// user -> User{Name: "non_existing", Age: 20} if not found

// 如果名为 “Jinzhu” 的 User 被找到,`Attrs` 会被忽略
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// SQL: SELECT * FROM USERS WHERE name = 'Jinzhu' ORDER BY id LIMIT 1;
// user -> User{ID: 111, Name: "Jinzhu", Age: 18} if found

为属性使用 Assign

Assign 方法允许您在结构上设置属性,不管是否找到记录。 这些属性设定在结构上,但不用于生成 SQL 查询,最终数据不会被保存到数据库。

// 根据所给条件和分配的属性初始化,不管记录是否存在
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
// user -> User{Name: "non_existing", Age: 20} if not found

// 如果找到了名为“Jinzhu”的用户,使用分配的属性更新结构体
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user)
// SQL: SELECT * FROM USERS WHERE name = 'Jinzhu' ORDER BY id LIMIT 1;
// user -> User{ID: 111, Name: "Jinzhu", Age: 20} if found

Assign 方法的主要作用是在应用程序层面上临时修改模型的属性,而不是持久化这些更改。这在处理复杂的业务逻辑时非常有用,因为它允许你在不更改数据库状态的情况下,根据需要调整模型的状态。此外,它还可以用于在创建新记录或更新现有记录之前,设置默认值或预设值。

虽然 Assign 方法不能持久化更改这些使用的数据,但可以间接性更改,上面例子里面被初始化后的结构体数据都存入了 &user 中,意味着我们如果要持久化更改这些在数据库对应的数据,就可以写多一条GORM操作语句进行数据操作。例如:

// 添加数据进数据库
// 假设没有找到记录,那么 user 将被初始化
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
// 随后可以创建新的记录
db.Create(&user)
// 更新现有数据库对应数据
// 假设找到了记录,并且 Age 被设置为 20
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user)
// 可以对 user 进行更多修改
user.Email = "jinzhu@example.com"
// 保存更改到数据库
db.Save(&user)
// 条件性更新
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 25}).FirstOrInit(&user)
// 检查模型的某个属性,决定是否更新
if user.Age != 25 {
 user.Age = 25
 db.Save(&user) // 只有当 Age 发生变化时才保存
}

做上述这些操作的时候要注意一些小细节:

  • 事务性:确保您的操作具有事务性,特别是在进行创建或更新操作时。
  • 并发问题:在并发环境中,需要注意其他可能同时修改相同记录的情况。
  • 数据验证:在保存模型到数据库之前,确保进行适当的数据验证和清理。

FirstOrInit, 以及 AttrsAssign, 提供了一种强大和灵活的方法来确保记录的存在,并且在一个步骤中以特定的属性初始化或更新。

FirstOrCreate

FirstOrCreate 用于获取(查询)与特定条件匹配的第一条记录,或者如果没有找到匹配的记录,创建一个新的记录。 这个方法在结构和map条件下都是有效的。 受 RowsAffected 影响的属性有助于确定创建或更新记录的数量。

原话:FirstOrCreate finds the first matching record, otherwise if not found creates a new instance with given conds.
// 如果没找到,就创建一个新纪录
result := db.FirstOrCreate(&user, User{Name: "non_existing"})
// SQL: INSERT INTO "users" (name) VALUES ("non_existing");
// user -> User{ID: 112, Name: "non_existing"}
// result.RowsAffected // => 1 (record created)

// 如果用户已经被找到,不会创建新纪录
result = db.Where(User{Name: "jinzhu"}).FirstOrCreate(&user)
// user -> User{ID: 111, Name: "jinzhu", Age: 18}
// result.RowsAffected // => 0 (no record created)

配合 Attrs 使用 FirstOrCreate

Attrs 可以用于指定新记录的附加属性。 这些属性用于创建,但不在初始搜索查询中。

// 如果没找到,根据额外属性创建新的记录
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
// SQL: SELECT * FROM users WHERE name = 'non_existing';
// SQL: INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
// user -> User{ID: 112, Name: "non_existing", Age: 20}

// 如果user被找到了,`Attrs` 会被忽略
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
// SQL: SELECT * FROM users WHERE name = 'jinzhu';
// user -> User{ID: 111, Name: "jinzhu", Age: 18}

配合 Assign 使用 FirstOrCreate

不管记录是否被找到,Assign 方法都会设置记录中的属性。 并且这些属性被保存到数据库。

// 如果没找到记录,通过 `Assign` 属性 初始化并且保存新的记录
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
// SQL: SELECT * FROM users WHERE name = 'non_existing';
// SQL: INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
// user -> User{ID: 112, Name: "non_existing", Age: 20}

// 通过 `Assign` 属性 更新记录
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 20}).FirstOrCreate(&user)
// SQL: SELECT * FROM users WHERE name = 'jinzhu';
// SQL: UPDATE users SET age=20 WHERE id = 111;
// user -> User{ID: 111, Name: "Jinzhu", Age: 20}
PREV
[Golang] GORM框架 Exec和Raw
NEXT
[Golang] GORM框架 Scope

评论(0)

发布评论