17

我想在我的 Doctrine-Entity 中实现一个人类可读的 ID。我想保留 DB-ID 以供工作并添加诸如“PRE12-00005”之类的内容(带有前缀和年份,并且每个新年都从 0 开始)。我尝试添加一个自定义 ID 生成器,但似乎 Doctrine 无法在一个实体中使用两个生成的值。

/**
 * @var integer
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
protected $id;

/**
 * @var string
 * @ORM\Column(name="name", type="string", length=25, unique=true)
 * @ORM\GeneratedValue(strategy="CUSTOM")
 * @ORM\CustomIdGenerator(class="NameGenerator")
 */
protected $name;

Doctrine 总是尝试将生成器的返回值保存到“id”-Field 中,并将 null 保存到“name”中。还有另一种实现方式吗?

4

1 回答 1

20

据我所知,GeneratedValue 策略是为主键保留的,这意味着每个实体只能使用一次。

但是,根据您的需要,您有几个选择:

  • 你总是可以有一个prePersist 生命周期事件,在你第一次持久化之前设置你喜欢的任何值。

  • 如果您依赖 id 从中生成另一个唯一 id,您可以实现一个 postPersist 事件,在那里设置您的名称并确保您刷新两次(第一次生成主键,第二次保存名称)。

  • 如果您认为数据库中的名称在一段时间内为空是可以的,则可以实现一个 postLoad 事件,如果名称为空,该事件将填充名称。这样,您的应用程序始终可以看到名称(因为它要么是从数据库加载的,要么是由 postLoad 事件填充的),并且当您在初始保存后第一次添加或编辑信息时,您的名称也将被保存

  • 不保存名称并由某些 cronjob/deamon/queue 生成它可能是可以的,这样您的应用程序就不必处理它。您唯一需要做的就是确保缺少的名称不会搞砸。

  • 也许生成一个不依赖于主键的键可能是可以的,因此可以由全局事件处理程序生成。你当然有这样一个事件处理程序的缺点,因为他是全局的,所以无论它是否是正确的实体,都会为你坚持的每个对象调用。

  • 最后但并非最不重要的一点是,回退到存储过程/触发器以让数据库处理它可能是可以的。这样你就不必在你的应用程序中弄乱这个了。但请注意,在此过程中可能存在陷阱(就像开发人员忘记了这一点,因为它不在代码中,而是在数据库中!)。

可能还有其他方法。我想说的是:不要将 generatedValue 用于非主键属性!

于 2012-12-17T15:44:42.810 回答