我有两个实体A和B,其中A有很多B(从A到B的单向多对多)。
在创建新A并为其分配B时,对连接表的约束失败,因为doctrine正在尝试为新A插入ID为0
的关联。这使我相信新A的INSERT具有那时候没有被执行。
/**
* @Entity
* @Table(name="a")
*/
class A {
/**
* @var int
* @Id @Column(type="integer") @GeneratedValue
*/
protected $id;
/**
* @var B[]
* @ManyToMany(targetEntity="B", fetch="LAZY")
* @JoinTable(name="jointable",
* joinColumns={@JoinColumn(name="a_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="b_id", referencedColumnName="id")}
* )
*/
protected $bs;
public function getBs() { return $this->bs; }
}
// I omit B here, because it is not important
// controller code:
$a = new A();
$a->getBs()->add($em->find(B::class, 8));
$em->persist($a);
$em->flush();
这是我得到的错误:
An exception occurred while executing 'INSERT INTO jointable (a_id, b_id) VALUES (?, ?)' with params [0, 8]:
SQLSTATE[23000]: Integrity constraint violation...
查看数据库(和查询日志),永远不会创建A.结果,与B#8的关联失败。
我怎样才能使学说得到这个权利?
答案 0 :(得分:0)
原来,学说确实一切正确。问题是我报告的这个PHP Bug:https://bugs.php.net/bug.php?id=71059
要使用Doctrine进行补偿,您有两种选择:
如果数据库中的所有布尔字段都是TINYINT(就像我一样),你可以简单地覆盖布尔类型:
Type::overrideType(Type::BOOLEAN, \Doctrine\DBAL\Types\TinyintBooleanType::class);
如果数据库中的所有布尔字段都不是TININT,则必须向doctrine添加新类型:
Type::addType(
\Doctrine\DBAL\Types\TinyintBooleanType::NAME,
\Doctrine\DBAL\Types\TinyintBooleanType::class
);
$entityManager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping(
Type::SMALLINT, \Doctrine\DBAL\Types\TinyintBooleanType::NAME
);
然后您可以在实体中使用此类型:
@Column(type="tinyintasbool")
<?php
namespace Doctrine\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* This type is appropriate when storing boolean values in TINYINT columns.
* @author Tobias Marstaller
*/
class TinyintBooleanType extends Type
{
const NAME = "tinyintasbool";
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if ($value === null)
{
return null;
}
else return $value? 1 : 0;
}
public function convertToPHPValue($value, AbstractPlatform $patform)
{
if ($value === null)
{
return null;
}
else return ((int) $value) === 0? false : true;
}
/**
* Gets the SQL declaration snippet for a field of this type.
*
* @param array $fieldDeclaration The field declaration.
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform The currently used database platform.
*
* @return string
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration);
}
/**
* Gets the name of this type.
*
* @return string
*
* @todo Needed?
*/
public function getName()
{
return static::NAME;
}
public function getBindingType()
{
return \PDO::PARAM_INT;
}
}