У меня есть следующая проблема с отображением наследования одной таблицы для Doctrine ORM, также известной как STI.
Кажется, что невозможно иметь ассоциацию oneToMany от объекта STI к другому объекту.
У меня есть 2 объекта Клиент и Поставщик с очень похожими полями. Вот почему я хочу использовать опцию наследования одной таблицы в Doctrine, чтобы получить эти 2 объекта в одной таблице с простым столбцом «тип», чтобы указать, к какому объекту принадлежит строка. Класс АннотацияБизнес будет служить классом базовый класс для этих двух объектов.
Рассмотрим это сопоставление сущностей для AbstractBusiness.
Axelvnk\CRMBundle\Entity\AbstractBusiness:
type: entity
table: axelvnk_crm_business
inheritanceType: SINGLE_TABLE
discriminatorColumn:
name: type
type: string
discriminatorMap:
customer: Axelvnk\CRMBundle\Entity\CustomerInterface
supplier: Axelvnk\CRMBundle\Entity\SupplierInterface
id:
id:
type: guid
generator:
strategy: UUID
fields:
vatNumber:
type: string
label:
type: string
oneToOne:
billingAddress:
targetEntity: Axelvnk\CRMBundle\Entity\AddressInterface
joinColumn:
name: billing_address_id
referencedColumnName: id
cascade: ["all"]
oneToMany:
addresses:
targetEntity: Axelvnk\CRMBundle\Entity\AddressInterface
mappedBy: business
cascade: ["all"]
Это будет сопоставление для объекта Customer.
Axelvnk\CRMBundle\Entity\Customer:
type: entity
Это будет сопоставление для сущности Поставщика.
Axelvnk\CRMBundle\Entity\Supplier:
type: entity
Дополнительных полей пока нет. Но это не имело бы значения для этого вопроса.
Теперь свойство AbstractBusiness::billingAddress ссылается на экземпляр объекта Адрес. Который отображается следующим образом:
Axelvnk\CRMBundle\Entity\Address:
type: entity
table: axelvnk_crm_address
id:
id:
type: guid
generator:
strategy: UUID
fields:
streetAndNumber:
type: string
city:
type: string
manyToOne:
business:
targetEntity: Axelvnk\CRMBundle\Entity\AbstractBusiness
inversedBy: addresses
joinColumn:
name: business_id
referencedColumnName: id
Как видите, свойство Адрес::бизнес ссылается на сущность STI, являющуюся AbstractBusiness. Это может быть либо Поставщик, либо Клиент в зависимости от стороны-владельца.
Я ожидаю, что доктрина решит, какой класс сущностей следует гидратировать, поскольку она знает, что AbstractBusiness является сущностью STI, и карта дискриминатора на месте. После запроса бизнес-таблицы с идентификатором business_id в адресной таблице он должен определить класс на основе столбца «тип» в адресной таблице, верно? Но, видимо, это не так. Я не могу вернуться к объекту STI, потому что доктрина не может создавать прокси-классы из абстрактных классов, что, я думаю, имеет смысл.
Но теперь у меня вопрос: как правильно сопоставить сущность STI? Или это просто невозможно в доктрине?
Спасибо за ваши ответы!
Но тогда базовый объект должен быть включен в карту дискриминатора... И тогда он, вероятно, попытается вместо этого перейти к этому классу, а это не то, чего я хочу.
Нет, не должно. Вот определение карты дискриминатора из реального проекта для разных типов контента. Базовая сущность называется Content, а не abstract: @ORM\DiscriminatorMap({"photo" = "Photo", "video" = "Video", "comics" = "Comics"})
Странно, какая версия? Это исключение, которое я получаю, когда делаю это: «Сущность« Axelvnk \ CRMBundle \ Entity \ Business »должна быть частью карты дискриминатора« Axelvnk \ CRMBundle \ Entity \ Business », чтобы быть правильно сопоставленным в иерархии наследования. В качестве альтернативы вы можно сделать «Axelvnk\CRMBundle\Entity\Business» абстрактным классом, чтобы избежать возникновения этого исключения».
В вашем случае я имею в виду, что AbstractBusiness не должен быть частью карты дискриминатора (и это не то, что я вижу) и не должен быть абстрактным классом. Business и Supplier должны быть инстанцируемыми классами, унаследованными от AbstractBusiness. Кстати, вы используете CustomerInterface вместо Customer в своей карте дискриминатора, возможно, это неправильно, попробуйте вместо этого использовать явные имена классов сущностей.
Не уверен, на что вы указываете. Почему это не должно быть абстрактно? И вы имеете в виду, что Customer и Supplier должны быть инстанцируемыми классами, которые расширяют AbstractBusiness, да, они уже есть. И я использую интерфейсы, да, но слушатель разрешает их из доктрины в фактические конкретные классы, не беспокойтесь.
Правильно ли эти разрешения интерфейса сохранены в ClassMetadata? Doctrine использует информацию из этого источника для своих операций.






Таким образом, очевидно, использование интерфейсов в DISCTORMAP, а затем использование распознавателя целевых объектов доктрины для замены этих интерфейсов конкретными классами отлично работает для сохранения объектов, но для их извлечения он не может понять, какой класс гидратировать...
Итак, решение: всегда используйте конкретные классы в DISCTORMAP...
На github есть открытая проблема для поддержки разрешения классов/интерфейсов в карте дискриминатора так же, как это работает для свойств targetEntity: https://github.com/doctrine/orm/issues/7622
У меня есть сопоставления ассоциаций с сущностями STI в моих проектах, и они работают нормально, но в моем случае базовая сущность не определена как
abstract.