2017-02-23 63 views
0

Я пытаюсь добавить ко всем моим доктринам сгенерированные объекты два поля для обработки дат (date_created и date_modified).doctrine 2 persist entity и исключить пустые поля из запроса на вставку

Пожалуйста, обратитесь к текущей 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 при сохраняющихся, сгенерированный запрос будет в любом случае содержат эти два поля. Это приводит к переопределению значений по умолчанию DEFAULT и ON UPDATE.

Во-первых, я заставил эти значения NULL переопределить значение по умолчанию CURRENT_TIMESTAMP, которое по умолчанию вводится типом datetime в doctrine.

$entity->setDateCreated(null); 
$entity->setDateModified(null); 

Затем после установки остальных значений я настойчив:

$em->persist($entity); 
$em->flush(); 

Входя запрос с 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 
     ) 

) 

SQL-результат как INSERT заявления от db:

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 глубоко внедрена в систему, над которой я работаю.

Также использование datetime в mysql также не является вариантом для этого конкретного проекта.

Я видел похожие темы, касающиеся управления датами, но в данном случае проблема касается только того факта, что я не могу полностью позволить MYSQL заботиться о создании и обновлении этих двух полей даты, поскольку doctrine persist/flush всегда будет перезаписываться с помощью сгенерированного оператора INSERT.

Я просматриваю обратные вызовы жизненного цикла, чтобы увидеть, могут ли они помочь не вставлять определенное поле, основанное на ряде параметров.

Следующий шаг будет возиться с источником orm.

Я надеюсь, что кто-то может помочь с вышеуказанным!

+0

Есть ли причина, по которой вы не используете обратный вызов доктрины доторсистов, чтобы управлять им? На мой взгляд, некоторая логика внутри базы данных не очень хорошо. – goto

+0

Я думаю, что вы делаете здесь хороший момент, моя проблема в том, что я работаю с сгенерированными объектами, и я перехожу к новому api, я пытаюсь решить это с минимальными усилиями в отношении доктрины. В этом смысле было бы полезно использовать даты обработки mysql. – Davide

+0

, если вы не хотите, чтобы переменные имели какие-либо данные и позволяли им обрабатывать mysql, почему бы вам просто не сделать так, чтобы они не были нужны? –

ответ

2

Не стоит настраивать doctrine, чтобы пропустить ввод значений null. Может возникнуть ситуация, когда в базе данных вам понадобятся значения null.

Возможно, вы должны установить значения по умолчанию в Entity i.e внутри constructor. Когда вы указываете значения по умолчанию. Доктрина автоматически примет эти значения, если они не указаны с setters.

В данном примере: вы должны иметь что-то вроде:

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

Я никогда не сталкивался с какими-либо проблем в этом подходе.

Надеюсь, это поможет!

+0

Привет, Джайл и, прежде всего, спасибо, ваше решение кажется единственным возможным способом до сих пор. Также эта дискуссия затрагивает ту же тему: [link] (https://github.com/doctrine/doctrine2/issues/5624). Тем не менее я удивлен, что нет способа исключить поле из вычисленной вставки на основе некоторого условия. – Davide

+0

Хотя я был бы рад, если бы был этот вариант вокруг 'doctrine'. Но, я понимаю, «Doctrine» - это всего лишь слой между «PHP» и «Mysql», который преобразует данные для обеих сторон. Поэтому может потребоваться пропустить столбец. – Jeet