Doctrine2实体使用varchar作为ID时无法将ID插入数据库

3
我正在尝试在ZF2应用程序中为Doctrine2创建实体。 我的实体应该有一个长度为15的id varchar,但是当我尝试创建新行时,doctrine2没有将此ID推送到数据库中。
在生成的实体类中,我有以下内容:
 /**
 * Checkpoints
 *
 * @ORM\Table(name="checkpoints", uniqueConstraints{@ORM\UniqueConstraint(name="sort", columns={"sort"})}, indexes={@ORM\Index(name="country", columns={"country"})})
 * @ORM\Entity
 */
  class Checkpoints
  {
     /**
     * @var string
     *
     * @ORM\Column(name="id", type="string", length=15, nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
     private $id;
  // rest of the entity...

我需要更改什么才能将这个表单中的ID传递到Doctrine Flush中的数据库中?

在执行 flush 操作之前,您是否将新实体“持久化”到 EntityManager 中以使其被管理? - ins0
当然。它添加了新行,但ID设置为null :( 还有许多其他插入的列。它是一个空表,因此任何新插入都会抛出异常,指出存在null值的ID。 - RoaK
你是否已经将你的MySQL列id设置为默认选项auto_increment并标记为primary key?如果是这样的话,那么请将Doctrine实体中的列类型从string更改为integer - ins0
好的,我明白了。但是当我从实体中获取它或将自动生成更改为NONE时,我会得到类似于以下内容的东西:“类型为App\Entity\Checkpoints的实体缺少字段'id'的分配ID。此实体的标识符生成策略要求在调用EntityManager#persist()之前填充ID字段。如果您想要自动生成标识符,您需要相应地调整元数据映射。”我的问题是 - 我应该更改什么以使id在插入时被传递而不是自动生成,但由表单中的值指定? - RoaK
也许我应该改变策略为无。在实体方法中插入setId,并在持久化之前将此ID设置为从表单获取的ID...我现在离开了,稍后再检查一下。你认为这样会行吗? - RoaK
显示剩余5条评论
2个回答

5
Doctrine对于@ORM\GeneratedValue(strategy="Identity")在不同的数据库中处理方式不同。在MySql中,它将插入一个生成的值,也称为AUTO_INCREMENT,其结果为integer作为ID。请参见http://docs.doctrine-project.org/en/2.0.x/reference/basic-mapping.html#identifiers-primary-keys
在您的情况下,您不应该使用GeneratedValue注释及其策略。因此,请完全删除它。如果您想要表单的ID,您可以在您的实体中设置一个构造函数,该构造函数将为该实体设置ID。
class Checkpoints {

   public function __constructor($id)
   {
       $this->id = $id;
   }

   /**
     * @var string
     *
     * @ORM\Column(name="id", type="string", length=15, nullable=false)
     * @ORM\Id
     */
     private $id;
  // rest of the entity...
}

请注意,不提及GeneratedValue注释与GenerateValue(strategy="None")相同。
当然,您可以在创建后稍后设置ID,但是此实体的每个实例都需要一个ID,因此最好通过构造函数强制设置它。
因此,在控制器中,您可能会使用类似以下内容:
if ($form->isValid() {
    $formData = $form->getData();
    $checkpoint = new Checkpoints($formData['id']);
}

正如您所提到的,您希望通过表单输入设置ID。但是让我指出,用户可能会输入重复的主键。为了捕获它,您必须检查对象是否已经存在,在这种情况下,我建议使用\DoctrineModule\Validator\NoObjectExists。请参见https://github.com/doctrine/DoctrineModule/blob/master/docs/validator.md关于Doctrine验证器的详细信息。
因此,为了检查是否存在具有ID的对象,您可以将此验证器添加到表单的输入过滤器中:
public function getInputFilterSpecification()
{
    $entityManager = $this->serviceManager->get('Doctrine\ORM\EntityManager');

    return array(
        'id' => array(
            'validators' => array(
                array(
                    'name' => 'DoctrineModule\Validator\NoObjectExists',
                    'options' => array(
                        'object_repository' => $entityManager->getRepository('Application\Entity\Checkpoints'),
                        'fields' => 'id'
                    )
                )
            )
        )
    );
}

现在我们知道提供的ID可以用于新的Checkpoints实体。

我已经按照您的建议完全完成了。唯一的区别是我的实体对象绑定到表单,因此实体对象具有ID的setter,并且由表单自动填充。 - RoaK
好的,水合器可以为您设置值;)因此,在这种情况下,您不需要像我在控制器中的示例中那样自己设置任何ID。因此,如果答案对您有帮助,您可以批准它。祝你好运! - Kwido

1

只需删除此行

* @ORM\GeneratedValue(strategy="IDENTITY")
创建实体并将记录插入到实体中

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接