私のエンティティは、IDにこの注釈を使用しています。
_/**
* @orm:Id
* @orm:Column(type="integer")
* @orm:GeneratedValue(strategy="AUTO")
*/
protected $id;
_
クリーンなデータベースから、古いデータベースから既存のレコードをインポートし、同じIDを保持しようとしています。次に、新しいレコードを追加するときに、MySQLに通常どおりID列を自動インクリメントさせます。
残念ながら、Doctrine2は指定されたIDを完全に無視するようです。
新しいソリューション
以下の推奨事項に従って、次が推奨されるソリューションです。
_$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
_
旧ソリューション
Doctrineはジェネレータ戦略を決定するためにClassMetaDataからピボットされるため、EntityManagerでエンティティを管理した後に変更する必要があります。
_$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$this->em->flush();
_
これをMySQLでテストしたところ、期待どおりに機能しました。つまり、カスタムIDを持つエンティティはそのIDで保存され、IDが指定されていないエンティティはlastGeneratedId() + 1
を使用しました。
ソリューションはMySQLで正常に動作しますが、シーケンスベースであるため、PostgreSQLで動作させることができませんでした。
この行を追加して、完全に機能するようにします。
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
宜しくお願いします、
おそらく何がdoctrineが変更されたが、今正しい方法は:
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
エンティティが クラステーブルの継承 の一部である場合、bothのクラスメタデータのid-generatorを変更する必要がありますエンティティ(永続化するエンティティとルートエンティティ)
新しいソリューションは、すべてのエンティティが挿入前にIDを持っている場合にのみ正常に機能します。 1つのエンティティにIDがあり、別のエンティティにはない場合-新しいソリューションは失敗します。
私はすべてのデータをインポートするためにこの関数を使用します:
function createEntity(\Doctrine\ORM\EntityManager $em, $entity, $id = null)
{
$className = get_class($entity);
if ($id) {
$idRef = new \ReflectionProperty($className, "id");
$idRef->setAccessible(true);
$idRef->setValue($entity, $id);
$metadata = $em->getClassMetadata($className);
/** @var \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata */
$generator = $metadata->idGenerator;
$generatorType = $metadata->generatorType;
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$unitOfWork = $em->getUnitOfWork();
$persistersRef = new \ReflectionProperty($unitOfWork, "persisters");
$persistersRef->setAccessible(true);
$persisters = $persistersRef->getValue($unitOfWork);
unset($persisters[$className]);
$persistersRef->setValue($unitOfWork, $persisters);
$em->persist($entity);
$em->flush();
$idRef->setAccessible(false);
$metadata->setIdGenerator($generator);
$metadata->setIdGeneratorType($generatorType);
$persisters = $persistersRef->getValue($unitOfWork);
unset($persisters[$className]);
$persistersRef->setValue($unitOfWork, $persisters);
$persistersRef->setAccessible(false);
} else {
$em->persist($entity);
$em->flush();
}
}
Solution for Doctrine 2.5 and MySQL
「新しいソリューション」は、Doctrine 2.5およびMySQLでは機能しません。使用する必要があります。
$metadata = $this->getEntityManager()->getClassMetaData(Entity::class);
$metadata->setIdGenerator(new AssignedGenerator());
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
ただし、他のDBMSをまだ試したことがないため、MySQLについてのみ確認できます。
a library を作成して、Doctrineエンティティの将来のIDを設定します。すべてのキューIDが消費されると、元のID生成戦略に戻り、影響を最小限に抑えます。このようなコードを繰り返す必要がないように、単体テスト用の簡単なドロップイン。
Villermen に触発されて、ライブラリ tseho/doctrine-assigned-identity を作成しました。これにより、IDを手動でDoctrineエンティティに割り当てることができます、エンティティがAUTO、SEQUENCE、IDENTITY、またはUUIDの状態を使用している場合でも。
あなたは本番環境で使用すべきではありませんが、機能テストには本当に役立ちます。
ライブラリは、割り当てられたIDを持つエンティティを自動的に検出し、必要な場合にのみジェネレーターを置き換えます。インスタンスにIDが割り当てられていない場合、ライブラリは初期ジェネレーターにフォールバックします。
ジェネレーターの置き換えは、Doctrine EventListenerで行われ、フィクスチャーにコードを追加する必要はありません。