1

I'm working on a project made in Symfony 3.1.10.

I have three entities:

MyEntity 1->n MyPivotEntity

MyPivotEntity n->1 MySuperInheritanceEntity

and I have another entity MyInheritanceEntity which inherit from MySuperInheritanceEntity with a single_table inheritance

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#single-table-inheritance

I made a CollectionType field of MyPivotEntity in MyEntityType form, but when I createForm from the controller I get a memory exceeded message, because the builder do a database request for each MySuperInheritanceEntity. How can I prevent this? In this case I don't need MySuperInheritanceEntity information at all, I just need MyPivotEntity fields

<?php 

/**
 * MyEntity
 *
 * @ORM\Table(name="my_entity")
 * @ORM\Entity()
 */
class MyEntity {
    /**
     * @ORM\OneToMany(targetEntity="MyPivotEntity", mappedBy="myEntity", cascade={"persist"})
     */
    private $myPivotEntity;
}

/**
 * MyPivotEntity
 *
 * @ORM\Table(name="my_pivot_entity")
 * @ORM\Entity()
 */
class MyPivotEntity {
    /**
     * @ORM\ManyToOne(targetEntity="MyEntity", inversedBy="myPivotEntity", cascade={"persist"})
     */
    private $myEntity;

    /**
     * @ORM\ManyToOne(targetEntity="MySuperInheritanceEntity", inversedBy="myPivotEntity", cascade={"persist"})
     */
    private $mySuperInheritanceEntity;
}

/**
 * MySuperInheritanceEntity
 *
 * @ORM\Table(name="my_super_inheritance_entity")
 * @ORM\Entity()
 * @ORM\InheritanceType("SINGLE_TABLE")
 */
class MySuperInheritanceEntity {
    /**
     * @ORM\OneToMany(targetEntity="MyPivotEntity", mappedBy="mySuperInheritanceEntity")
     */
    private $myPivotEntity;
}

/**
 * MyInheritanceEntity
 *
 * @ORM\Table(name="my_inheritance_entity")
 * @ORM\Entity()
 */
class MyInheritanceEntity extends MySuperInheritanceEntity {

}

class MyEntityType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('myPivotEntity', CollectionType::class, [
                'entry_type' => MyPivotEntityType::class
            ]);
    }
}


class MyPivotEntityType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('somField');
    }
}

class MyController extends Controller {
    /**
     * @Post("/myEntity/update")
     */
    public function postMyEntityUpdateAction(Request $request, MyEntity $myEntity) {
        $form = $this->createForm(MyEntityType::class, $myEntity);

        // here error 500 because of too mach memory
        // caused by the MyPivotEntityType which runs a request for each entry,
        // trying to retrieve all the information about MySuperInheritanceEntity and MyInheritanceEntity
        // even if I don't need it at all
        // because of the @ORM\InheritanceType("SINGLE_TABLE")
        // deleting the inheritance solves the problem, but I need it

        $form->handleRequest($request);

        if ($form->isValid()) {
            $this->getEm()->flush();
            return ['success' => true];
        }

        $errors = (string) $form->getErrors(true, false);
        throw new HttpException(400, $errors);
    }
}
2
  • insufficient information. edit your question. remove all that descriptive sentences about you entities. share code for your entities, super simplified (include just class-level and property-level mapping information and association) Commented Oct 23, 2018 at 8:40
  • Ok, I updated the post, I put all the needed code and a description of the problem in the controller, after the createForm Commented Oct 23, 2018 at 18:35

1 Answer 1

1

The documentation says:

There is a general performance consideration with Single Table Inheritance: If the target-entity of a many-to-one or one-to-one association is an STI entity, it is preferable for performance reasons that it be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).

Also keep in mind:

use plural names for OneToMany association propertiy names:

class MyEntity {
        /**
         * @ORM\OneToMany(targetEntity="MyPivotEntity", mappedBy="myEntity", cascade={"persist"})
         */
        private $myPivotEntities;
}

Update

As an alternative way, you may totaly forget about the inheritance and have separate (previously child) entities with all properties and associations replicated.

Sign up to request clarification or add additional context in comments.

6 Comments

Ok, thank you for your answer. I already knew that, I everytime try to avoid to use the single_table or joined inheritance, but it's not something I create, and I cannot edit the structure now. Is there a way to change the way the builder do the request, maybe omitting the property mySuperInheritanceEntity from myPivotEntity when it tries to get the fields of the collection?
should you keep this Single Table architecture & entity definition and associations?
Yes, I can't change it, there will be too many impacts on the existent project
unfortunately, that is impossible. Documentation obviously says : “Doctrine CANNOT create proxy instances of this entity and will ALWAYS load the entity eagerly.”
So if I have to change the structure, I have to make a OneToMany to a entity joined with the STI entity in a oneToOne relation? Can this be a solution?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.