简体   繁体   中英

Primary key and foreign key at the same time with doctrine 2

I have the two tables :

table A with id as primary key

table B with id as primary key and foreign key

Explanation on short:

I need to have in table B a primary key that also to be a foreign key that points to table A 's primary key.

Can anybody explain me how to map this by annotations in Doctrine 2?

Note:

I tried it By this :

   class A
{
    /**
     * @var bigint $id
     *
     * @Column(name="id", type="bigint", nullable=false)
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $a_id;
...

and B table:


class B
{
    /**
     * @var bigint $id
     * @Id 
     * @OneToOne(targetEntity="A", fetch="LAZY")
     * @JoinColumn(name="id", referencedColumnName="id")
     */
    private $b_id;
...

But it gives me this error:

Uncaught exception 'Doctrine\\ORM\\Mapping\\MappingException' with message 'No identifier/primary key specified for Entity 'B'. Every Entity must have an identifier/primary key.' in /var/www/agr-reg-php/Doctrine/ORM/Mapping/MappingException.php:37 Stack trace:

NB: I must not have composite primary key.

This is possible since Doctrine 2.1 :

Identity through Foreign Entities or derived entities : You can now use a foreign key as identifier of an entity. This translates to using @Id on a @ManyToOne or @OneToOne association. You can read up on this feature in the tutorial .

I could solve the problem, creating a pk field with the same name to the foreign field

class B
{
/**
 * @var bigint $a_id
 * @Id @Column(name="a_id", type="bigint", nullable="false")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $a_id;

/**
 * @OneToOne(targetEntity="A", fetch="LAZY")
 * @JoinColumn(name="id", referencedColumnName="id")
 */
private $a;
.
.
.
/**
 * @var A
 *
 * @ORM\OneToOne(targetEntity="A")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="a_id", referencedColumnName="id", unique=true)
 * })
 */
private $a;
//...

Well this is other temporal solution for insert:

    /**
     * @Entity
     * @Table(name="types")
     */
    class Type {
    /**
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    private $id;
    /**
     * @OneToMany(targetEntity="type\models\Language", mappedBy="type")
     */
    private $languages;

    /**
     * @Column(type="string", length = 45,nullable = true)
     */
    private $category;

    /**
     * @Column(type="string", length = 1)
     */
    private $status;

    /**
     * @Column(type="string", length = 45)
     */
    private $name;

    /**
     * @Column(type="datetime", nullable = true)
     */
    private $datedeleted;

    /**
     * @Column(type="datetime", nullable = true)
     */
    private $datemodificated;

    /**
     * @Column(type="datetime")
     */
    private $dateregistered;

    public function __construct() {
        $this->languages = new \Doctrine\Common\Collections\ArrayCollection;
        $this->status = 1;
        $this->dateregistered = new \DateTime("now");
    }

    public function id() {
            return $this->id;
    }

    public function category($value = NULL) {
        if (is_null($value))
            return $this->category;
        else
            $this->category = $value;
    }

    public function name($value = NULL) {
        if (is_null($value))
            return $this->name;
        else
            $this->name = $value;
    }

    public function status($value = NULL) {
        if (is_null($value))
            return $this->status;
        else
            $this->status = $value;
    }

    public function datedeleted($value = NULL) {
        if (is_null($value))
            return $this->datedeleted;
        else
            $this->datedeleted = $value;
    }

    public function datemodificated($value = NULL) {
        if (is_null($value))
            return $this->datemodificated;
        else
            $this->datemodificated = $value;
    }

    public function dateregistered($value = NULL) {
        if (is_null($value))
            return $this->dateregistered;
        else
            $this->dateregistered = $value;
        }
    }

    /**
     * @Entity
     * @Table(name="languages")
     */
    class Language {

    /**
     * @Id 
     * @Column(name="type_id", type="integer", nullable="false")
     */
    private $language_id;

    /**
     * @Id
     * @ManyToOne(targetEntity="type\models\Type",inversedBy="languages")
     * @JoinColumn(name="type_id", referencedColumnName="id")
     */
    private $type;

    /**
     * @Column(type="string", length = 100, nullable = true)
     */
    private $description;

    /**
     * @Id
     * @Column(type="string", length = 20)
     */
    private $language;

    public function language_id($value) {
        $this->language_id = $value;
    }

    public function description($value = NULL) {
        if (is_null($value))
            return $this->description;
        else
            $this->description = $value;
    }

    public function language($value = NULL) {
        if (is_null($value))
            return $this->language;
        else
            $this->language = $value;
    }

    public function type($value = NULL) {
        if (is_null($value))
            return $this->type;
        else
            $this->type = $value;


     }
    }

$language = new Language;
$xtype_id = $this->em->find("Type",1);
$language->language_id($xtype_id->id());
$language->type($xtype_id);
$language->description($xdescription);
$language->language($xlanguage);
$this->em->persist($this);
$this->em->flush();

this insert in a Class With the foreign key and primary key in language

I had the same task and experimentaly found this solution:

class A {  
    /**  
    * @Id @Column(type="integer", nullable=false)  
    * @GeneratedValue  
    */  
    protected $id;  

    /**  
     * @OneToOne(targetEntity="B", inversedBy="a", orphanRemoval=true, cascade={"persist", "remove"})  
     * @JoinColumn(name="id", referencedColumnName="id")  
     */  
    protected $b;  

}  

class B {  
    /**  
     * @OneToOne(targetEntity="A", mappedBy="b" )  
     */  
    protected $user;  

    /**  
     * @Id  
     * @Column(type="integer", nullable=false)  
     * @GeneratedValue  
     */  
    protected $id;  

}  

Finally I resolved my problem by specifying two fields in my entity class for the same column from real table. The changes are made only in class B (look at the question for class A):


class B
{
    /**
     * @var bigint $id
     * @Id @Column(name="id", type="bigint", nullable="false")
     */
    private $b_id;

    /**
     * @OneToOne(targetEntity="A", fetch="LAZY")
     * @JoinColumn(name="id", referencedColumnName="id")
     */
    private $a;

...

In fact all what I have done is write two fields in my entity for the same primary key and foreign key.

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