我的 Symfony 项目(sf v6)使用 postgresql/postgis 和 2 个数据库:主要一个包含特定业务数据,第二个称为 web-services 数据库,其公共数据在多个项目之间共享(有两个模式,主要是 gis其中包含 GIS 数据)
首先,我参考了https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
并设置我的 config/package/doctrine.yaml :
doctrine:
dbal:
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
server_version: '13.5'
web_services:
url: '%env(resolve:DATABASE_WS_URL)%'
server_version: '13.5'
default_connection: default
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
#auto_generate_proxy_classes: true # thow exception Unrecognized options
#enable_lazy_ghost_objects: true # thow exception Unrecognized options
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
type: attribute
#profiling: "%kernel.debug%" # thow exception Unrecognized options
#profiling_collect_backtrace: '%kernel.debug%' # thow exception Unrecognized options
web_services:
connection: web_services
mappings:
Web_services:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity/WebServices'
prefix: 'App\Entity\WebServices'
alias: Web_services
type: attribute
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod:
doctrine:
orm:
auto_generate_proxy_classes: false
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system
主要是dbalurl和connectiondir和prefix
我可以毫无问题地访问default连接、实体、存储库!
我定义了两个实体来访问 web_services 连接数据:
第一个,翻译
// src/Entity/WebServices/Translate.php
namespace App\Entity\WebServices;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Id;
#[ORM\Entity(repositoryClass: 'App\Repository\WebServices\TranslateRepository')]
#[ORM\Table(name: "gis.translate")]
class Translate
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $translateId;
#[ORM\Column(type: 'string', length: 255)]
private $frValue;
#[ORM\Column(type: 'string', length: 255)]
private $gbValue;
public function getTranslateId(): ?int
{
return $this->translateId;
}
// and others getters/setters
}
第二个,国家
// src/Entity/WebServices/Country.php
namespace App\Entity\WebServices;
use App\Repository\WebServices\CountryRepository;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Id;
#[ORM\Entity(repositoryClass: 'App\Repository\WebServices\CountryRepository')]
#[ORM\Table(name: "gis.country")]
class Country
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $countryId = null;
#[ORM\Column(length: 2, nullable: true)]
private ?string $isoCode = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(name: 'translate_id', referencedColumnName: 'translate_id', nullable: false)]
private ?Translate $translate = null;
public function getCountryId(): ?int
{
return $this->country_id;
}
// and others getters/setters
}
请注意,web_services表使用tablename_id,而不仅仅是id
此时,如果我运行(在我的 sf docker 容器中,postgresql 在另一个容器中):
php bin/console dbal:run-sql 'SELECT * FROM translate'
主数据库转换表,或php bin/console dbal:run-sql --connection web_services 'SELECT * FROM gis.translate'
用于 web_services 数据库转换表,如果我在 src/Controller/WebServices/CountryController 中调用
EntityManager的
getClassMetadata
方法,它也会在 LocationCountryController 控制器中正确运行:
[…]
use Doctrine\ORM\EntityManagerInterface;
[…]
#[Route(path: '/location/country')]
class LocationCountryController extends AbstractController
{
#[Route(path: '/', name: 'location_country_index', methods: ['GET'])]
public function index(EntityManagerInterface $web_servicesEntityManager): Response
{
$ctableName = $web_servicesEntityManager->getClassMetadata(Country::class);
$ttableName = $web_servicesEntityManager->getClassMetadata(Translate::class);
dd($ctableName, $ttableName);
}
//[…]
}
如果我运行,总是在 src/Controller/WebServices/CountryController:
class LocationCountryController extends AbstractController
{
#[Route(path: '/', name: 'location_country_index', methods: ['GET'])]
public function index(EntityManagerInterface $web_servicesEntityManager): Response
{
$connection = $doctrine->getConnection('web_services');
$countries = $connection->fetchAllAssociative('SELECT * FROM country c JOIN translate t ON c.translate_id=t.translate_id LIMIT 20');
dd($countries);
// […]
它返回了 20 个具有正确翻译数据的国家!
但是一旦我想使用国家存储库,例如,总是在src/Controller/WebServices/CountryController:
namespace App\Controller;
use App\Entity\WebServices\Country;
use App\Entity\WebServices\Translate;
use App\Repository\WebServices\CountryRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
#[Route(path: '/location/country')]
class LocationCountryController extends AbstractController
{
#[Route(path: '/', name: 'location_country_index', methods: ['GET'])]
public function index(ManagerRegistry $doctrine, EntityManagerInterface $web_servicesEntityManager): Response
{
$repository = $web_servicesEntityManager->getRepository(Country::class);
$countries = $repository->findAll(); // ->find(1) returns same error
dd($countries);
// or
$countriesRepository = $doctrine->getRepository(Country::class, 'web_services');
dd($countriesRepository->findAll());
//[…]
我有错误:
An exception occurred while executing a query: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "gis.country" does not exist
这是我的src/Repository/WebServices/CountryRepository.php:
namespace App\Repository\WebServices;
use App\Entity\WebServices\Country;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Country>
*
* @method Country|null find($id, $lockMode = null, $lockVersion = null)
* @method Country|null findOneBy(array $criteria, array $orderBy = null)
* @method Country[] findAll()
* @method Country[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CountryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Country::class);
}
// […]
/**
* @return country[] Returns an array of Country objects
*/
public function findAll(): array
{
return $this->createQueryBuilder('c')
// ->innerJoin('c.translate', 't')
// ->addSelect('t')
// ->orderBy('t.frValue', 'ASC')
->setMaxResults(5)
->getQuery()
->getResult()
;
}
我将 symfony 更新到了最新的 6.3 版本,最新的 2.17 版本,但仍然有同样的错误!
在我要解决的搜索中,我发现了这篇文章:https://dba.stackexchange.com/questions/101570/error-42p01-relation-does-not-exist...权限不好...但我可以访问表,如果我不使用存储库!如果我搜索“postgresql Error 42P01”,我就会找到这篇文章:
PostgreSQL 错误:42P01:关系“[表]”不存在
我的
translate
和 country
表似乎命名正确。
编辑:
我尝试在实体中分离schema和table:
#[ORM\Table(schema: "sig", name: "country")]
,不变!
问题出在注册表的配置上。 Symfony 自动装配将搜索与配置匹配的第一个模式。 在这种情况下,App\Entity 永远是第一位的。
这个问题有两种解决方案:
首先是把最奇特的定义放在第一位。
另一种是将实体放在单独的文件夹中。