我正在尝试向我的所有 Doctrine 生成的实体添加两个字段来处理日期(date_created 和 date_modified)。
请查看当前的 yml 以供引用
`Project\PasswordRecovery:
type: entity
table: PasswordRecovery
lifecycleCallbacks:
prePersist: [ prePersist ]
indexes:
fk_PasswordRecovery_User_idx:
columns:
- user_id
id:
id:
type: integer
generator:
strategy: AUTO
fields:
date_created:
type: datetime
nullable: false
columnDefinition: 'TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP'
options:
default: CURRENT_TIMESTAMP
date_modified:
type: datetime
nullable: false
columnDefinition: 'TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
options:
default: CURRENT_TIMESTAMP
token:
type: text
nullable: true
user_id:
type: integer
nullable: true
manyToOne:
users:
targetEntity: User
inversedBy: passwordRecoveries
joinColumn:
name: user_id
referencedColumnName: id
我的问题:
正如您在下面的sql表CREATE信息中看到的那样,MYSQL可以在插入或更新查询时正确处理当前时间戳。
CREATE TABLE `PasswordRecovery` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`date_modified` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`token` longtext COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`),
KEY `fk_PasswordRecovery_User_idx` (`user_id`),
CONSTRAINT `FK_41CD3A90A76ED395` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `PasswordRecovery` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`date_modified` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`token` longtext COLLATE utf8_unicode_ci,
PRIMARY KEY (`id`),
KEY `fk_PasswordRecovery_User_idx` (`user_id`),
CONSTRAINT `FK_41CD3A90A76ED395` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
但是,当持久化上面的实体时,即使我在持久化时强制将 $date_created 和 $date_modified 设置为 null,生成的查询在任何情况下都将包含这两个字段。 这会导致覆盖 sql DEFAULT 和 ON UPDATE 值。
首先,我将这些值强制设置为 NULL 以覆盖 CURRENT_TIMESTAMP 默认值,该默认值是由 Doctrine 中的日期时间类型强加的默认值。
$entity->setDateCreated(null);
$entity->setDateModified(null);
然后在设置剩余值后我坚持:
$em->persist($entity);
$em->flush();
通过使用 Doctrine 的 DebugStack 记录查询,我获得以下信息:
Array
(
[1] => Array
(
[sql] => "START TRANSACTION"
[params] =>
[types] =>
[executionMS] => 0.000178098678589
)
[2] => Array
(
[sql] => INSERT INTO PasswordRecovery (date_created, date_modified, token, user_id) VALUES (?, ?, ?, ?)
[params] => Array
(
[1] =>
[2] =>
[3] => stackoverflow test insert
[4] => 14
)
[types] => Array
(
[1] => datetime
[2] => datetime
[3] => text
[4] => integer
)
[executionMS] => 0.00274181365967
)
[3] => Array
(
[sql] => "COMMIT"
[params] =>
[types] =>
[executionMS] => 0.000401973724365
)
)
来自数据库的作为 INSERT 语句的 SQL 结果:
INSERT INTO `PasswordRecovery` (`id`, `user_id`, `date_created`, `date_modified`, `token`)
VALUES
(21, 14, NULL, NULL, 'stackoverflow test insert');
预期结果:
INSERT INTO `PasswordRecovery` (`id`, `user_id`, `date_created`, `date_modified`, `token`)
VALUES
(23, 14, '2017-02-23 08:28:23', '2017-02-23 08:28:23', 'stackoverflow test insert');
到目前为止,我还没有找到一种方法来根据某些条件或数据跳过插入字段。将 'nullabe' 设置为 false 或 true 似乎没有任何区别。
使用查询生成器不是一个选项,因为 EntityManager 持久性方案深深 Root 于我正在使用的系统中。
对于这个特定项目来说,在 mysql 中使用日期时间也不是一个选项。
我见过关于日期管理的类似线程,但在这种情况下问题仅涉及这样一个事实:我无法完全让 MYSQL 负责生成和更新这两个日期字段,因为坚持/刷新 Doctrine 将始终存在使用生成的 INSERT 语句覆盖它们。
我正在研究生命周期回调,看看它们是否有助于不根据多个参数插入某些特定字段。
下一步将摆弄 orm 源。
希望有人能帮忙解决以上问题!
最佳答案
为了跳过插入 null
值而配置 doctrine
并不是一个好主意。在某些情况下,您可能需要数据库中的 null
值。
您可能应该在Entity
中设置默认值,即在构造函数
中。当您提供默认值时。当setters
未提供这些值时,Doctrine将自动获取这些值。
对于当前示例:您应该具有以下内容:
public function __construct()
{
$this->created_at = new \DateTime();
}
我在这种方法中从未遇到过任何问题。
希望这有帮助!
关于php - Doctrine 2 保留实体并从插入查询中排除空字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42410655/