Since version v2.8, if the time fields created_at, updated_at, and deleted_at are integer fields, the ORM component will automatically recognize and support them, writing second-level timestamp values.

Example SQL

This is the MySQL table structure used in the subsequent example code.

  1. CREATE TABLE `user` (
  2. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  3. `name` varchar(45) NOT NULL,
  4. `status` tinyint DEFAULT 0,
  5. `created_at` int(10) unsigned DEFAULT NULL,
  6. `updated_at` int(10) unsigned DEFAULT NULL,
  7. `deleted_at` int(10) unsigned DEFAULT NULL,
  8. PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  10. CREATE TABLE IF NOT EXISTS `user_detail` (
  11. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  12. `address` varchar(45) NOT NULL,
  13. PRIMARY KEY (`id`)
  14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Time Fields - Integer Fields - 图1tip

If you try to test viewing the SQL statements executed by ORM operations, it’s recommended to enable debug mode (related documentation: ORM Senior - Debug Mode), the SQL statements will be automatically printed to log output.

created_at Writing Time

When executing the Insert/InsertIgnore/BatchInsert/BatchInsertIgnore methods, this time is automatically written. Subsequent update/delete operations will not change the content of the created_at field.

Time Fields - Integer Fields - 图2warning

It should be noted that the Replace method will also update this field because this operation is equivalent to deleting the existing old data and writing a new data record.

  1. // INSERT INTO `user`(`name`,`created_at`,`updated_at`,`deleted_at`) VALUES('john',1731481488,1731481488,0)
  2. g.Model("user").Data(g.Map{"name": "john"}).Insert()
  3. // INSERT IGNORE INTO `user`(`id`,`name`,`created_at`,`updated_at`,`deleted_at`) VALUES(10000,'john',1731481518,1731481518,0)
  4. g.Model("user").Data(g.Map{"id": 10000, "name": "john"}).InsertIgnore()
  5. // REPLACE INTO `user`(`id`,`name`,`created_at`,`updated_at`,`deleted_at`) VALUES(10000,'john',1731481747,1731481747,0)
  6. g.Model("user").Data(g.Map{"id": 10000, "name": "john"}).Replace()
  7. // INSERT INTO `user`(`id`,`name`,`created_at`,`updated_at`,`deleted_at`) VALUES(10001,'john',1731481766,1731481766,0) ON DUPLICATE KEY UPDATE `id`=VALUES(`id`),`name`=VALUES(`name`),`updated_at`=VALUES(`updated_at`),`deleted_at`=VALUES(`deleted_at`)
  8. g.Model("user").Data(g.Map{"id": 10001, "name": "john"}).Save()

deleted_at Soft Delete

When soft deletion is present (i.e., the deleted_at field exists), all query statements will automatically add conditions for deleted_at.

  1. // UPDATE `user` SET `deleted_at`=1731481948 WHERE (`id`=10) AND `deleted_at`=0
  2. g.Model("user").Where("id", 10).Delete()

Changes occur when querying:

  1. // SELECT * FROM `user` WHERE (id>1) AND `deleted_at`=0
  2. g.Model("user").Where("id>?", 1).All()

You can see that when the deleted_at field exists in the data table, all query operations involving the table automatically add the condition deleted_at=0.

updated_at Update Time

When executing the Save/Update methods, this time is automatically written. It should be noted that the Replace method will also update this field because it is equivalent to deleting the existing old data and writing a new data record.

Time Fields - Integer Fields - 图3info

If the deleted_at soft delete field also exists, the update operation statement will also contain the deleted_at condition.

  1. // UPDATE `user` SET `name`='john guo',`updated_at`=1731481821 WHERE (`name`='john') AND `deleted_at`=0
  2. g.Model("user").Data(g.Map{"name" : "john guo"}).Where("name", "john").Update()
  3. // UPDATE `user` SET `status`=1,`updated_at`=1731481895 WHERE `deleted_at`=0 ORDER BY `id` ASC LIMIT 10
  4. g.Model("user").Data("status", 1).OrderAsc("id").Limit(10).Update()
  5. // INSERT INTO `user`(`id`,`name`,`created_at`,`updated_at`,`deleted_at`) VALUES(1,'john guo',1731481915,1731481915,0) ON DUPLICATE KEY UPDATE `id`=VALUES(`id`),`name`=VALUES(`name`),`updated_at`=VALUES(`updated_at`),`deleted_at`=VALUES(`deleted_at`)
  6. g.Model("user").Data(g.Map{"id": 1, "name": "john guo"}).Save()

Scenarios of Joint Table Queries

If several tables involved in an associated query have enabled the soft delete feature, the following situation will occur, where all relevant tables will have soft deletion time judgment added to the condition statements.

  1. // SELECT * FROM `user` AS `u` LEFT JOIN `user_detail` AS `ud` ON (ud.id=u.id) WHERE (`u`.`id`=10) AND `u`.`deleted_at`=0 LIMIT 1
  2. g.Model("user", "u").LeftJoin("user_detail", "ud", "ud.id=u.id").Where("u.id", 10).One()

Control the Granularity of Time Writing

The time field value writing in this chapter is by default in seconds-level timestamp. But if we want to control the granularity of time writing such as writing a millisecond-level timestamp, how do we do it? We can use Time Fields - SoftTimeOption.