具有自动增量的Doctrine自定义ID

时间:2017-02-04 19:40:24

标签: entity-framework symfony doctrine-orm

我想用前缀定义一些id。

例如,对于一个订单实体,它:“OR17000001” 在此示例中,前缀为“OR17”

所以我声明了我的id实体:

/**
 * @var string
 *
 * @ORM\Column(name="id", type="string", length=8)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="CUSTOM")
 * @ORM\CustomIdGenerator(class="My\Bundle\Generator\OrderCodeGenerator")
 */
private $id;

我的发电机是:

<?php

namespace My\Bundle\Generator;

use Doctrine\ORM\Id\AbstractIdGenerator;
use Doctrine\ORM\EntityManager;    
use My\Bundle\Entity\Order;

class OrderCodeGenerator extends AbstractIdGenerator
{
    /**
      * Format :
     * $prefix - string
     * $year - take 2 first letters (17)
     * $increment - Take the last code + 1
     *
     * @param EntityManager $em
     * @param \Doctrine\ORM\Mapping\Entity $entity
     * @return bool|string
     */
    public function generate(EntityManager $em, $entity)
    {
        if ($entity instanceof Order) {
            $now = new \DateTime();
            $year = $now->format('y');
            $prefix = 'OR';

            $maxCode = $em->getRepository('MyRepo:Order')->findMaxCode($year, $prefix);

            if ($maxCode) {
                $increment = substr($maxCode[1], -4);
                $increment = (int)$increment + 1;
            } else
                $increment = 0;

            $code = $prefix . $year . sprintf('%04d', $increment);
            return $code;
        }

        return false;
    }
}

不要忘记方法findMaxCode:

public function findMaxCode($year, $prefix)
{
    $qb = $this->createQueryBuilder('entity');

    $qb->where($qb->expr()->like('entity.id', ':code'))
        ->setParameter('code', '%' . $prefix . $year . '%');

    $qb->select($qb->expr()->max('entity.id'));

    return $qb->getQuery()->getOneOrNullResult();
}

这很好用=)

我的问题是当我尝试同时添加一些实体时。 我的情况是:

  • 订购包含某些商品的实体(其形式集合)
  • 项目实体

所以我需要使用此策略自定义项目订单ID。问题是找到最大代码。我有这个错误:

  

SQLSTATE [23000]:完整性约束违规:1062 Duplicata du   冠军'IT170000001'pour la clef'PRIMARY'

生成器无法找到生成第二项的最大代码,因为没有刷新。

如何在刷新之前将增量值保存在2 id之间?

解决方案:

我保留了我的物品的数字ID。它对我的Order实体很有用,它比简单的int更具可读性。但我不关心物品。

致Honza Rydrych

1 个答案:

答案 0 :(得分:2)

查询DB以获取最后插入的ID,然后插入“+ one”并不是可靠的解决方案。 我对这种情况的解决方案是让doctrine以标准方式生成ID,并在需要提供数据时添加前缀“OR / Year /”。

(Optionaly你可以编写自定义的Twig扩展来呈现ID http://symfony.com/doc/current/templating/twig_extension.html