Использование отношений с несколькими менеджерами сущностей

Мне интересно, возможно ли создать отношения между двумя сущностями, которые находятся в отдельных базах данных.

Например, если мы взяли решение, найденное здесь 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- при необходимости измените настройки. Надеюсь, поможет.

Другие вопросы по тегам