Model Creation
Model
The Model
method is used to create a Model
object based on a data table. Commonly, you can also use the Model
method in the g
object management module to create a Model
object on the default database configuration.
Usage example:
g.Model("user")
// Or
g.DB().Model("user")
Additionally, in certain scenarios, you can switch the database object of the current model through the DB
method, for example:
m := g.Model("user")
m = m.DB(g.DB("order"))
This is equivalent to the following operation:
m := g.DB("user").Model("user")
Raw
The Raw
method is used to create a Model
object based on a raw SQL
statement. You can also use the ModelRaw
method in the g
object management module to create a Model
object on the default database configuration given an SQL
statement.
s := "SELECT * FROM `user`"
m, _ := g.ModelRaw(s).WhereLT("age", 18).Limit(10).OrderAsc("id").All()
// SELECT * FROM `user` WHERE `age`<18 ORDER BY `id` ASC LIMIT 10
s := "SELECT * FROM `user` WHERE `status` IN(?)"
m, _ := g.ModelRaw(s, g.Slice{1,2,3}).WhereLT("age", 18).Limit(10).OrderAsc("id").All()
// SELECT * FROM `user` WHERE `status` IN(1,2,3) AND `age`<18 ORDER BY `id` ASC LIMIT 10
Chaining Safety
Chaining Safety
is simply the distinction between two ways of model operations: one modifies the current model
object (unsafe, default), and one does not (safe) but requires using assignment operations for model property modification/condition stacking, that's all.
Default Situation
By default, gdb
is non-chaining safe
, meaning each method of the chaining operation will modify the Model
properties of the current operation. Hence, the Model
object cannot be reused. For instance, when there are separate query conditions, we can use the Model
object as follows:
user := g.Model("user")
user.Where("status", g.Slice{1,2,3})
if vip {
// Automatically stack query conditions, modifying the current model
user.Where("money>=?", 1000000)
} else {
// Automatically stack query conditions, modifying the current model
user.Where("money<?", 1000000)
}
// vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
r, err := user.All()
// vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
n, err := user.Count()
As observed, if chaining operations are executed separately, each operation in the chain will modify the existing Model
object, and the query conditions will automatically stack, so the user
object cannot be reused; otherwise, conditions will keep stacking. Also, in this usage mode, whenever we need to operate on the user
table, we must use syntax like g.DB().Table("user")
to create a new user
model object, which can be quite cumbersome.
By default, considering performance and GC optimization, model objects are non-chaining safe
to prevent creating too many temporary model objects.
However, it should be noted that if you are using dao
generated by the cli tool gen dao
, like user := dao.User.Ctx(ctx)
, the obtained user
Model
object is chaining safe by default (automatically called .Safe()
).
Clone
Method
Additionally, you can manually invoke the Clone
method to clone the current model, creating a new model to achieve chaining safety. Since it is a new model object, there is no concern about modifying the existing model object, for example:
// Define a user model singleton
user := g.Model("user")
// Clone a new user model
m := user.Clone()
m.Where("status", g.Slice{1,2,3})
if vip {
m.Where("money>=?", 1000000)
} else {
m.Where("money<?", 1000000)
}
// vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
r, err := m.All()
// vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
n, err := m.Count()
Safe
Method
Of course, you can set the current model to be chaining safe
through the Safe
method, and each subsequent chaining operation will return a new Model
object that can be reused. However, it is important to note that modifications to model properties or stacking of operation conditions need to be achieved through variable assignments (m = m.xxx
) to overwrite the original model object, for example:
// Define a user model singleton
user := g.Model("user").Safe()
m := user.Where("status", g.Slice{1,2,3})
if vip {
// Query conditions stacked through assignment
m = m.Where("money>=?", 1000000)
} else {
// Query conditions stacked through assignment
m = m.Where("money<?", 1000000)
}
// vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
r, err := m.All()
// vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
// !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
n, err := m.Count()
As seen, the user model singleton object user
in the example can be reused without worrying about being "polluted". Under this chaining safety approach, we can create a user singleton object user
and reuse it in various subsequent queries. However, when there are multiple query conditions, condition stacking needs to be achieved through model assignment operations (m = m.xxx
).
After using the Safe
method, each chaining operation will create a new temporary model object (using Clone
internally to achieve model cloning), thereby achieving chaining safety. This usage is quite common in model operations.