Search code examples
doctrinedoctrine-ormdoctrine-odm

ODM: Cannot achieve bi-directional relationship


I have two documents. I am trying to find all papers that are associated to a specific person. The documents are saving in their collections, and a reference is being created from Person to Paper, but not the other way around.

/** @ODM\Document */
class Paper
{
/**
 * @ODM\Id
 */
protected $id;

/** @ODM\ReferenceOne(targetDocument="Person", cascade={"all"}, mappedBy="papers") */
protected $person;


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

public function __set($property, $value) {
    $this->$property = $value;
}


public function toArray() {
    return get_object_vars($this);
}
}
/** @ODM\Document */
class Person
{
/**
 * @ODM\Id
 */
protected $id;

/** @ODM\ReferenceMany(targetDocument="Paper", cascade={"all"}, inversedBy="person") */
protected $papers;


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

public function __set($property, $value) {
    $this->$property = $value;
}


public function toArray() {
    return get_object_vars($this);
}
}

CREATE A NEW BI-DIRECTIONAL REFERENCE

$person = $dm->getRespository('Person')->find($person_id);

$paper = new Paper();
$person->papers->add($paper);

$dm->persist($person);
$dm->flush();

Later in the code, this query returns 0 results; shouldn't it be returning papers written by specified person?

$papers = $dm->createQueryBuilder('Paper')
    ->field('person.$id')->equals(new \MongoId($person_id_as_string))
    ->getQuery()->execute();

Solution

  • If Paper::person is annotated with "mappedBy" it means that Paper is not the "owning side" and doctrine will not persist any changes to Paper::person.

    To make your query work, make Paper the owning side so Paper stores the reference to Person.

    /** @ODM\Document */
    class Person
    {
        /** @ODM\ReferenceMany(targetDocument="Paper", mappedBy="person") */
        protected $papers;
    }
    
    /** @ODM\Document */
    class Paper
    {    
        /** @ODM\ReferenceOne(targetDocument="Person", inversedBy="papers") */
        protected $person;
    }
    

    Creating a paper and persisting a reference to person:

    $person = $dm->getRespository('Person')->find($person_id);
    
    $paper = new Paper();
    $paper->person = $person;
    
    $dm->persist($paper);
    $dm->flush();
    

    Querying Papers by $person:

    $papers = $dm->createQueryBuilder('Paper')
        ->field('person')->references($person)
        ->getQuery()->execute();