doctrine 2持久化实体并从插入查询中排除空字段

时间:2017-02-23 08:36:34

标签: php mysql symfony doctrine-orm 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表中看到的,MYSQL下面的CREATE信息可以在插入或更新查询时正确处理当前时间戳。

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;

然而,当持久化上面的实体时,即使我在持久化时强制设置为null $ date_created和$ date_modified,生成的查询在任何情况下都将包含这两个字段。 这会导致覆盖sql DEFAULT和ON UPDATE值。

首先,我将这些值强制为NULL以覆盖CURRENT_TIMESTAMP默认值,默认值由doctrine中的datetime类型强制为默认值。

$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
        )

)

db中的sql结果为INSERT语句

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 persitence方案深深植根于我正在使用的系统中。

同样在mysql中使用datetime也不是这个特定项目的选项。

我见过关于日期管理的类似线程但在这种情况下问题只涉及这样一个事实:我无法完全让MYSQL关注生成和更新这两个日期字段,因为doctrine persist / flush将始终用生成的INSERT语句覆盖这些。

我正在调查生命周期回调,看看这些回调是否有助于不根据大量参数插入某些特定字段。

下一步将是摆弄orm来源。

我希望有人可以帮助解决上述问题!

1 个答案:

答案 0 :(得分:2)

配置doctrine以跳过插入null值不是一个好主意。可能存在数据库中需要null值的情况。

您应该在Entity中设置默认值,即constructor内的默认值。提供默认值时。如果未从setters提供,则Doctrine将自动获取这些值。

对于当前示例:您应该具有以下内容:

public function __construct()
{
    $this->created_at = new \DateTime();
}

我从未在这种方法中遇到任何问题。

希望这有帮助!