简体   繁体   中英

Using abstract subclass in Doctrine : curious database generation

I'm currently working on an Symfony2 / mySQL project using Doctrine2. In our conception, we have a "super" abstract class which is extended by abstract subclasses wich are themselves extended by concrete classes.

Here's my code :

<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;

/**
 * Description of SuperAbstractClass
 *
 * @author gbrugiere
 * @ORM\Table(name="superabstractclass")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string", length=2)
 * @ORM\DiscriminatorMap({"AC" = "AbstractClass","C1" = "ConcreteClass1", "C2" = "ConcreteClass2"})
 */
abstract class SuperAbstractClass {
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="label", type="text", nullable=false)
     */
    protected $label;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set libellé
     *
     * @param string $label
     * @return SuperAbstractClass
     */
    public function setLabel($label)
    {
        $this->label = $label;

        return $this;
    }

    /**
     * Get libellé
     *
     * @return string 
     */
    public function getLabel()
    {
        return $this->label;
    }
}
?>

And then :

<?php

namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of SuperAbstractClass
 *
 * @author gbrugiere
 * @ORM\Table(name="abstractclass")
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string", length=2)
 * @ORM\DiscriminatorMap({"C1" = "ConcreteClass1", "C2" = "ConcreteClass2"})
 */
abstract class AbstractClass extends SuperAbstractClass {

    /**
     * @var string
     *
     * @ORM\Column(name="souslibelle", type="text", nullable=false)
     */
    protected $sousLibelle;

    /**
     * Set sous-libellé
     *
     * @param string $sousLibelle
     * @return AbstractClass
     */
    public function setSousLibelle($sousLibelle)
    {
        $this->sousLibelle = $sousLibelle;

        return $this;
    }

    /**
     * Get sous-libellé
     *
     * @return string 
     */
    public function getSousLibelle()
    {
        return $this->sousLibelle;
    }
}
?>

And here's my last code :

<?php

namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of ConcreteClass1
 *
 * @author gbrugiere
 * @ORM\Table(name="concreteclass1")
 * @ORM\Entity
 */
class ConcreteClass1 extends AbstractClass {

    /**
     * @var string
     *
     * @ORM\Column(name="details", type="text", nullable=false)
     */
    private $details;

    /**
     * Set details
     *
     * @param string $details
     * @return ConcreteClass1
     */
    public function setDetails($details)
    {
        $this->details = $details;

        return $this;
    }

    /**
     * Get details
     *
     * @return string 
     */
    public function getDetails()
    {
        return $this->details;
    }
}
?>

When I generate my SQL Code, I get :

CREATE TABLE superabstractclass (id INT AUTO_INCREMENT NOT NULL, libelle LONGTEXT NOT NULL, discr VARCHAR(2) NOT NULL, PRIMARY KEY(id)) 
DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE abstractclass (id INT NOT NULL, subLabel LONGTEXT NOT NULL, PRIMARY KEY(id)) 
DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE concreteclass1 (id INT NOT NULL, details LONGTEXT NOT NULL, PRIMARY KEY(id)) 
DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE concreteclass2 (id INT NOT NULL, detailsautres LONGTEXT NOT NULL, PRIMARY KEY(id)) 
DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

ALTER TABLE abstractclass 
ADD CONSTRAINT FK_438A1A85BF396750 FOREIGN KEY (id) 
REFERENCES superabstractclass (id) ON DELETE CASCADE;

ALTER TABLE concreteclass1 
ADD CONSTRAINT FK_474E75CFBF396750 FOREIGN KEY (id) 
REFERENCES superabstractclass (id) ON DELETE CASCADE;

I'm a bit surprised by the last line. Why is my concreteclass1 table referencing the superabstractclass (see *FK_474E75CFBF396750* ) and not the abstractclass . I'm worriing for my data integrity : what would happen if I delete an abstractclass line. I would still have a superabstractclass and a concreteclass1 line (meaning objet instances) but I would have lost some pieces of informations on my objects.

Am I missing something ? I've been searching for few hours now but wasn't able to find anything. Thank you for any help.

I recommend the following setup:

/**
 * @ORM\MappedSuperclass
 */
abstract class SuperAbstractClass {...}

and

/**
 * @ORM\MappedSuperclass
 */
abstract class AbstractClass extends SuperAbstractClass {...}

and

/**
 * @ORM\Table(name="concreteclass1")
 * @ORM\Entity
 */
class ConcreteClass1 extends AbstractClass {...}

This will create only one table in your schema (named concreteclass1) and having all attributes of your Concrete, Abstract and SuperAbstractClass. Still you can use generic functionality (eg id generation will work).

If you have an additional ConcreteClass it will create a new table/entity then again inheriting anything you'll need.

We have this setup as well - from my understanding there is no need to have a joined inheritance here.

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