Doctrine2 - получить идентификатор объекта перед очисткой

Есть ли способ получить идентификатор объекта перед сохранением/сбросом? Я имею в виду:

$entity = new PointData();
$form   = $this->createForm(new PointDataType(), $entity);

Если я попытаюсь использовать $entity->getId() в этот момент, он ничего не вернет.

Я могу заставить его работать:

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

(предположим, что $em = $this->getDoctrine()->getEntityManager();)

Как я могу этого добиться?


person Xavi    schedule 07.05.2012    source источник
comment
Прочтите о стратегии генерации идентификаторов на страницах документации Doctrine.   -  person Crozin    schedule 07.05.2012
comment
Спасибо Крозин. Я уже читал все это. Я не пытаюсь получить следующий автоматический индекс. Это не удастся, если 2 пользователя вызовут это действие одновременно.   -  person Xavi    schedule 07.05.2012


Ответы (6)


Если вы хотите узнать идентификатор объекта до того, как он будет сохранен в базе данных, вы, очевидно, не сможете использовать сгенерированные идентификаторы. Вам нужно будет найти способ самостоятельно генерировать уникальные идентификаторы (возможно, какая-то хэш-функция может создавать достаточно уникальные значения).

Однако это редко бывает хорошей идеей, поэтому вы должны быть осторожны.

Я бы очень тщательно подумал о том, зачем мне нужно знать идентификатор перед сбросом. Doctrine довольно хорошо позволяет вам создавать большой граф объектов и сохранять/сбрасывать его все сразу. Кажется вероятным, что в вашей архитектуре есть что-то уродливое, что вы пытаетесь обойти. Это может быть хорошей идеей, чтобы просмотреть это, прежде чем идти по маршруту, сгенерированному приложением.

person timdev    schedule 08.05.2012
comment
Большое спасибо за Ваш ответ. - person Xavi; 11.05.2012
comment
Возможно, вы могли бы использовать UUID для этой задачи, так как они практически уникальны (en.wikipedia.org/wiki/Universally_unique_identifier), и их можно сгенерировать заранее, например, из PHP. Мне они не очень нравятся, но было бы хорошим решением. - person JorgeeFG; 05.01.2017
comment
@JorgeeFG - Абсолютно. UUID отлично подходят для этого варианта использования. За годы, прошедшие с тех пор, как я написал этот ответ, я начал предпочитать UUID в качестве идентификаторов сущностей. github.com/ramsey/uuid — довольно надежная библиотека для их создания, и github.com/ramsey/uuid-doctrine предоставляет хорошо работающую реализацию типа доктрины. - person timdev; 05.01.2017
comment
На самом деле, сам Окрамиус (руководитель проекта Doctrine ORM) рекомендует генерировать наши собственные UUID вместо того, чтобы полагаться на Doctrine для этого... Одна из причин этого заключается в том, что таким образом мы можем иметь действительные сущности с момента их создания, узнайте, какой идентификатор у них будет, прежде чем сохранять их... - person ClemC; 23.04.2019

Вы можете использовать аннотацию @PostPersist. Метод, аннотированный этим, будет выполнен непосредственно перед завершением сброса, и идентификатор объекта уже будет доступен.

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/events.html

postPersist — событие postPersist происходит для сущности после того, как сущность стала постоянной. Он будет вызываться после операций вставки в базу данных. Сгенерированные значения первичного ключа доступны в событии postPersist.

<?php

use Doctrine\ORM\Mapping as ORM;

/** 
 * @ORM\Entity 
 * @ORM\HasLifecycleCallbacks 
 */
class PointData
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
     private $id;

     ...

     /** 
      * @ORM\PostPersist 
      */
     public function onPostPersist()
     {
         // Put some simple logic here that required the auto-generated Id.

         $this->doSomething($this->id);
     }
    
     ...

}
person Elier    schedule 20.06.2017
comment
Вероятно, было бы лучше использовать прослушиватель событий, если вы используете Symfony, но все же +1 - person gogaz; 13.06.2019
comment
Я предпочитаю аннотировать сущность, чтобы логика не скрывалась в другом месте. - person Elier; 05.06.2020

рекомендации Doctrine говорит:

Вам следует избегать автоматически сгенерированных идентификаторов. потому что:

  • Ваши операции с БД будут блокировать друг друга
  • Вы запрещаете массовые вставки
  • Вы не можете совершать транзакции с несколькими запросами
  • Ваш объект недействителен, пока не будет сохранен
  • Ваш объект не работает без БД

Таким образом, вместо этого вы можете использовать UUIDS.

public function __construct() {
     $this->id = Uuid::uuid4();  
}

Кроме того, Doctrine поддерживает UUID начиная с версии 2.3.

person mohamed abohassan    schedule 23.01.2020

$em = $this->getDoctrine()->getManager();
$entity = new PointData();

$em->persist($entity);

$entity->getId() <-- return <int>

$em->flush();

после сохранения вы можете получить идентификатор

person ProMix    schedule 08.02.2020
comment
Добро пожаловать в StackOverflow. Хорошо предоставлять фрагмент кода в качестве решения, но ответы, содержащие только код, считаются плохой практикой. Пожалуйста, объясните, что делает этот фрагмент и как он решает проблему. - person Foued MOUSSI; 08.02.2020

вы можете использовать автоматически сгенерированный идентификатор, чтобы получить ключ, такой как универсальные уникальные идентификаторы (UUID), или вы можете использовать события symfony: postFlush — событие postFlush происходит в конце операции сброса.

person achraf akrouti    schedule 06.09.2018

Не уверен, зачем вам нужен идентификатор перед очисткой, но если вам действительно нужно сохранить объект без сохранения в базе данных, вы можете попробовать использовать Транзакции.

Попробуйте что-то вроде этого:

$em->beginTransaction();
$em->persist($entity);
$em->flush();
$id = $entity->getId();
//do some stuff and save when ready
$em->commit();
person SpicyTacos23    schedule 28.04.2021