简体   繁体   中英

oneToMany association for single inheritance entity

I have following issue with the single table inheritance mapping for Doctrine ORM aka STI.

It seems as if it's impossible to have a oneToMany association from the STI entity to another entity.

I have 2 entities Customer and Supplier , with very similar fields. Which is why I want to use the single table inheritance option in Doctrine to get these 2 entities in one table with a simple 'type' column so to indicate what entity the row belongs to. AbstractBusiness class will serve as a base class for these 2 entities.

Consider this entity mapping for 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"]

This would be the mapping for the Customer entity

Axelvnk\CRMBundle\Entity\Customer:
    type: entity

This would be the mapping for the Supplier entity

Axelvnk\CRMBundle\Entity\Supplier:
    type: entity

For the time being no additional fields. But it wouldn't make a difference for this issue.

Now the AbstractBusiness::billingAddress property refers to an instance of an Address entity. Which is mapped like this :

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

As you can see the Address::business property refers back to the STI entity, being the AbstractBusiness. This can be either a Supplier or a Customer depending on the owning side..

I would expect doctrine to resolve which entity class to hydrate to since it knows AbstractBusiness is a STI entity and the discriminator map is in place. After querying the business table with the business_id in the address table, it should be able to figure out the class based on the "type" column in the address table, right? But apparently it doesn't. I can't map back to the STI entity because doctrine can't make proxy classes from Abstract classes, which makes sense I guess.

But my question now is, what is the right way to map back to the STI entity? Or is this just impossible in Doctrine?

Thank you for your answers!

So apparently, using interfaces in the discriminatorMap and then using the doctrine target entity resolver to replace these interfaces with concrete classes works perfectly to persist entities, but to fetch them, it can't figure out what class to hydrate...

So the solution : always use concrete classes in the discriminatorMap...

There's an open issue on github to support resolving the classes/interfaces in the discriminator map the same way it works for targetEntity properties : https://github.com/doctrine/orm/issues/7622

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM