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:

  1. g.Model("user")
  2. // Or
  3. g.DB().Model("user")

Additionally, in certain scenarios, you can switch the database object of the current model through the DB method, for example:

  1. m := g.Model("user")
  2. m = m.DB(g.DB("order"))

This is equivalent to the following operation:

  1. 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.

  1. s := "SELECT * FROM `user`"
  2. m, _ := g.ModelRaw(s).WhereLT("age", 18).Limit(10).OrderAsc("id").All()
  3. // SELECT * FROM `user` WHERE `age`<18 ORDER BY `id` ASC LIMIT 10
  1. s := "SELECT * FROM `user` WHERE `status` IN(?)"
  2. m, _ := g.ModelRaw(s, g.Slice{1,2,3}).WhereLT("age", 18).Limit(10).OrderAsc("id").All()
  3. // 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:

  1. user := g.Model("user")
  2. user.Where("status", g.Slice{1,2,3})
  3. if vip {
  4. // Automatically stack query conditions, modifying the current model
  5. user.Where("money>=?", 1000000)
  6. } else {
  7. // Automatically stack query conditions, modifying the current model
  8. user.Where("money<?", 1000000)
  9. }
  10. // vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
  11. // !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
  12. r, err := user.All()
  13. // vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
  14. // !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
  15. 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. (Smile)

ORM Model - Model - 图2tip

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:

  1. // Define a user model singleton
  2. user := g.Model("user")
  1. // Clone a new user model
  2. m := user.Clone()
  3. m.Where("status", g.Slice{1,2,3})
  4. if vip {
  5. m.Where("money>=?", 1000000)
  6. } else {
  7. m.Where("money<?", 1000000)
  8. }
  9. // vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
  10. // !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
  11. r, err := m.All()
  12. // vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
  13. // !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
  14. 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:

  1. // Define a user model singleton
  2. user := g.Model("user").Safe()
  1. m := user.Where("status", g.Slice{1,2,3})
  2. if vip {
  3. // Query conditions stacked through assignment
  4. m = m.Where("money>=?", 1000000)
  5. } else {
  6. // Query conditions stacked through assignment
  7. m = m.Where("money<?", 1000000)
  8. }
  9. // vip: SELECT * FROM user WHERE status IN(1,2,3) AND money >= 1000000
  10. // !vip: SELECT * FROM user WHERE status IN(1,2,3) AND money < 1000000
  11. r, err := m.All()
  12. // vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money >= 1000000
  13. // !vip: SELECT COUNT(1) FROM user WHERE status IN(1,2,3) AND money < 1000000
  14. 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).

ORM Model - Model - 图3tip

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.