Использование отношений с несколькими менеджерами сущностей
Мне интересно, возможно ли создать отношения между двумя сущностями, которые находятся в отдельных базах данных.
Например, если мы взяли решение, найденное здесь http://symfony.com/doc/current/cookbook/doctrine/multiple_entity_managers.html и создали отношение один-ко-многим с пользователями в базе данных клиентов для сообщений в базе данных по умолчанию.
Это то, что поддерживается Symfony2 и Doctrine?
2 ответа
Использование разных диспетчеров объектов (менеджеров объектов) не позволяет пересекать графы объектов. Этот случай слишком сложен и не управляется Doctrine ORM.
Если вам нужен такой случай, оставьте графы объектов отключенными, сохранив идентификаторы связанных объектов (старый стиль) вместо ссылки на них, а затем вручную получите объекты через сервисы. Вы можете найти довольно хороший пример того, как это будет работать, на примере связи между Doctrine2 ORM и Doctrine2 MongoDB ODM. В качестве альтернативы, вы также можете использовать @PostLoad
слушатель событий, который заполняет данные в ваших сущностях, создавая ссылку через репозитории, которые я связал в этом примере. То же самое для @PostPersist
(который должен вместо этого извлечь идентификаторы для связанных объектов), но имейте в виду, что эта техника может стать очень грязной.
Кроме того, если ваша СУБД поддерживает операции с несколькими базами данных на одном хосте, вы можете просто использовать один EntityManager и ссылаться на другую таблицу с помощью @ORM\Table(name="schemaname.tablename")
,
Это очень старый вопрос, но он все еще связан с Symfony (теперь 6.2), поэтому я дам ему быстрое обновление, поскольку это стоило мне около месяца борьбы с двумя сущностями из-за его неточности.
Решением всех моих проблем была эта маленькая вещь:
#[ORM\Table(schema: 'name_of_database')]
добавьте этот атрибут в свою сущность и вуаля — теперь она будет использовать это имя базы данных при создании SQL-запроса для этой сущности. Но по сути это жесткое кодирование имени базы данных для этого объекта — оно не будет меняться в разных средах (например, при тестировании или другой настройке).
Чтобы исправить это, я добавил новый прослушиватель к событию Doctrine.loadClassMetadata
, который меняет схему для выбранных объектов, когда переменная env изменяется наtest
:
namespace App\EventListener;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Events;
#[AsDoctrineListener(event: Events::loadClassMetadata, priority: 500)]
class DoctrineListener
{
public function loadClassMetadata(LoadClassMetadataEventArgs $event): void
{
if ('test' !== ($_ENV['APP_ENV'] ?? false)) {
return;
}
$meta = $event->getClassMetadata();
if (property_exists($meta, 'table') && isset($meta->table['schema'])) {
$meta->table['schema'] .= '_test';
}
if (!property_exists($meta, 'associationMappings')) {
return;
}
// ManyToMany tables
foreach ($meta->associationMappings as $i => $associationMapping) {
if (!isset($associationMapping['joinTable']['schema'])) {
continue;
}
$meta->associationMappings[$i]['joinTable']['schema'] .= '_test';
}
}
}
Благодаря этому вы также можете иметь динамическийschema
- при необходимости измените настройки. Надеюсь, поможет.