Ich habe eine Situation, in der ich Spalten zu einer Viele-zu-Viele Join-Tabelle hinzufügen muss, also versuche ich die empfohlene Praxis der Join-Tabelle durch eine Entität mit ManyToOne-Beziehungen mit jedem der anderen beiden vertreten Entitäten.Doctrine ManyToMany Association Entity: Warum löscht removeXXX() den zugrunde liegenden Datenbankeintrag nicht?
In diesem Fall haben wir ein Gericht Dolmetscher-Management-System, wo es eine Entität namens Event, eine andere namens Interpreter. Die InterpreterAssignment-Entität ist Eins-zu-Viele mit beiden, benötigt aber auch zwei Metadatenspalten: eine created
datetime und die Application\Entity\User
, die sie erstellt hat (ich lasse letzteres der Einfachheit halber aus).
So funktioniert das ganz gut:
$interpreter = $entityManager->getRepository('Application\Entity\Interpreter')
->findOneBy(['lastname'=>'Mintz']);
$assignment = new Entity\InterpreterAssignment();
$assignment->setInterpreter($interpreter)->setEvent($event);
$event->addInterpretersAssigned($assignment);
$em->flush();
... und ich brauche nicht einmal persist()
zu sagen, weil der cascade={"persist","remove"})
auf Event#interpretersAssigned
.
aber wenn ich versuche, das Gegenteil zu tun, das heißt, die removeInterpretersAssigned()
Methode verwenden, die Lehre für mich schrieb:
$event = $entityManager->find('Application\Entity\Event',103510);
$assignment = $event->getInterpretersAssigned()[0];
$event->removeInterpretersAssigned($assignment);
$em->flush();
die Datenbank unberührt; Doctrine löscht die Zeile in der Join-Tabelle nicht.
Ich kann umgehen mit sagen $entityManager->remove($assignment)
. Aber ich kann nicht anders, als zu denken, dass $event->removeInterpretersAssigned($assignment)
soll funktionieren.
Also, ich muss etwas vermissen, aber ich kann nicht sehen was. Das Doctrine cli-Tool sagt, dass meine Mappings in Ordnung sind. Hier sind die Einheiten in relevanten Teilen:
/* namespace declarations and use statements omitted */
class Event
{
/* other fields and methods omitted */
/**
* @ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="event",cascade={"persist","remove"})
* @var InterpreterAssignment[]
*/
protected $interpretersAssigned;
/* the following created by the Doctrine cli tool */
/**
* Remove interpretersAssigned
*
* @param \Application\Entity\InterpreterAssignment $interpretersAssigned
*/
public function removeInterpretersAssigned(\Application\Entity\InterpreterAssignment $interpretersAssigned)
{
$this->interpretersAssigned->removeElement($interpretersAssigned);
}
/**
* Get interpretersAssigned
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getInterpretersAssigned()
{
return $this->interpretersAssigned;
}
}
class Interpreter
{
/**
* @ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="interpreter")
* @var InterpreterAssignment[]
*/
protected $assignments;
/**
* Remove assignment
*
* @param \Application\Entity\InterpreterAssignment $assignment
*/
public function removeAssignment(\Application\Entity\InterpreterAssignment $assignment)
{
$this->assignments->removeElement($assignment);
}
/**
* Get assignments
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getAssignments()
{
return $this->assignments;
}
}
und hier ist der InterpreterAssignment
/**
* @ORM\Entity
* @ORM\Table(name="interp_events", uniqueConstraints={@ORM\UniqueConstraint(name="unique_deft_event",columns={"interp_id","event_id"})})
* @ORM\HasLifeCycleCallbacks
*/
class InterpreterAssignment
{
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Interpreter",inversedBy="assignments")
* @ORM\JoinColumn(name="interp_id", referencedColumnName="interp_id")
* @var Interpreter
*/
protected $interpreter;
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Event",inversedBy="interpretersAssigned")
* @ORM\JoinColumn(name="event_id", referencedColumnName="event_id")
* @var Event
*/
protected $event;
/**
* @ORM\Column(type="datetime",nullable=false)
* @var \DateTime
*/
protected $created;
/**
* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->created = new \DateTime();
}
/**
* Set interpreter
*
* @param \Application\Entity\Interpreter $interpreter
*
* @return InterpreterAssignment
*/
public function setInterpreter(\Application\Entity\Interpreter $interpreter)
{
$this->interpreter = $interpreter;
return $this;
}
/**
* Get interpreter
*
* @return \Application\Entity\Interpreter
*/
public function getInterpreter()
{
return $this->interpreter;
}
/**
* Set event
*
* @param \Application\Entity\Event $event
*
* @return InterpreterAssignment
*/
public function setEvent(\Application\Entity\Event $event)
{
$this->event = $event;
return $this;
}
/**
* Get event
*
* @return \Application\Entity\Event
*/
public function getEvent()
{
return $this->event;
}
/* other stuff ommitted */
}
Vielen Dank.
Dies funktioniert. Vielen Dank! Die einzige zusätzliche Modifikation, die notwendig war, war die Signatur der 'InterpreterAssignment' Entität zu ändern. SetEvent() akzeptiert NULL: 'public function setEvent (Ereignis $ event = null)' – David
BTW: Ich sehe klarer, warum einige Leute gegen ORM protestieren . Wenn die Eigenschaft "$ event" von "InterpreterAssignment" NULL-zulässig ist, ist dies nicht zulässig. Bemerkenswert ist, dass ich die Spalte in der Datenbank nicht nullbar machen konnte. – David