2016-06-24 14 views
0

Ok so in einem Wort: Hilfe!Doctrine 2 Lazy Ladeproblem in ZF2 Projekt

Es gibt etwas, das ich nicht herausfinden kann. In ZF2 benutze ich das wunderbare Doctrine Orm Module. Alles ist perfekt, aber heute habe ich etwas Seltsames entdeckt. Ich vermute, da muss irgendwo ein Fehler sein, den ich nicht finden kann. Oder vielleicht gibt es etwas, was ich in Doktrin 2 nicht klar verstehe.

Ich habe meine Entitäten zugeordnet. Wenn ich eine Viele-zu-Eins-Beziehung ohne Angabe der Abrufoption habe, wenn ich eine Entität durch Aufrufen der Methode find() in meinem Repository erhalte, kann ich sehen, dass mein Attribut wie erwartet eine Instanz der generierten Proxyklasse enthält. Aber wenn ich den Setter auf dieses Attribut anrufe, dann enthält es immer noch die empty-Instanz der Proxy-Klasse ???

Es scheint, dass Doctrine die Instanz nicht mit meiner Entität verknüpft bekommen kann. In meinem Fall ist die Entität, die ich von der find() -Methode erhalte, der Eigentümer der Beziehung.

Wenn ich die Abrufoption für EAGER in meinem Mapping angeben, gibt die find() -Methode eine Entität mit dem Attribut zurück, das erwartungsgemäß die Instanz der Klasse enthält, die in der Relation angegeben ist.

Hat jemand jemals das gleiche Problem gehabt?

Edit: Ok, also habe ich ein neues ZF2-Projekt erstellt, um sicherzustellen, dass nichts dazwischenkommt. So habe ich zwei Entitäten Gruppen und Benutzer:

/** 
* Class Group 
* @package Application\Entity 
* @Entity 
* @Table("`group`") 
*/ 
class Group 
{ 
    /** 
    * @Id 
    * @GeneratedValue 
    * @Column(type="integer", options={"unsigned"=true}) 
    */ 
    private $id; 

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

    /** 
    * @OneToMany(targetEntity="User", mappedBy="group") 
    */ 
    private $users; 
} 

/** 
* Class User 
* @package Application\Entity 
* @Entity 
* @Table(name="user") 
*/ 
class User 
{ 
    /** 
    * @Id 
    * @GeneratedValue 
    * @Column(type="integer", options={"unsigned"=true}) 
    */ 
    private $id; 

    /** 
    * @Column(type="string") 
    */ 
    private $firstName; 

    /** 
    * @Column(type="string") 
    */ 
    private $lastName; 

    /** 
    * @ManyToOne(targetEntity="Group", inversedBy="users") 
    * @JoinColumn(name="groupId", referencedColumnName="id") 
    */ 
    private $group; 
} 

Natürlich habe ich alle Getter und Setter in beiden Klassen habe, aber ich habe sie nicht im Beispiel setze schnell zu gehen.

Und in meinem Controller kann ich eine ganz einfache Sache, ohne die Sicht zu testen:

$user = $this->serviceLocator->get('doctrine.entitymanager.orm_default')->getRepository('Application\Entity\User')->find(1); 
var_dump($user->getGroup());exit; 

Die Var_dump Displays:

object(DoctrineORMModule\Proxy\__CG__\Application\Entity\Group)[367] 
    public '__initializer__' => 
    object(Closure)[362] 
    public '__cloner__' => 
    object(Closure)[363] 
    public '__isInitialized__' => boolean false 
    private 'id' (Application\Entity\Group) => int 1 
    private 'name' (Application\Entity\Group) => null 

Natürlich habe ich in den Datenbank-Benutzer und Gruppen hinzugefügt und ich habe einen Benutzer mit der ID 1 in einer Gruppe in der Tabellengruppe.

Vielleicht habe ich eine Option oder etwas verpasst? Um das Doctrine-Modul zu konfigurieren, folgte ich einfach dem Dokument auf github, also gab ich hier den Annotationstreiber und das Verzeichnis für meine Entitäten und natürlich die Datenbankanmeldeinformationen.

+0

Es klingt wie Sie etwas ziemlich einfach vermissen, aber es ist unmöglich, ohne weitere Details zu sagen. Sie könnten Ihre Frage verbessern, indem Sie Code anzeigen, insbesondere die relevanten Mapping-Direktiven und Ihre Repository-Nutzung. – timdev

+0

Ok, ich habe einige Details hinzugefügt: Ich habe ein Mini-Projekt erstellt, um sicher zu sein, dass alles sauber ist. Ich habe den Code meiner Entitäten und meinen Test geschrieben. Noch einmal, wenn ich fetch = "EAGER" in die Benutzereinheit für die Gruppenbeziehung setze, ist alles in Ordnung. Aber ohne es ... – Bruce

+1

Das sieht auf den ersten Blick gut aus. Also, was passiert als nächstes? Wenn "der Setter für dieses Attribut aufgerufen wird, dann enthält es immer noch die empty-Instanz der Proxy-Klasse" passiert? – timdev

Antwort

2

Dies ist ein völlig zu erwartendes Verhalten, da die Doktrin lazy-loading Ihre Gruppenentität ist. Dies liegt daran, alles, was Sie tun, ist dies:

$user->getGroup(); 

ich versuchen zu erklären, warum Sie nur einen Proxy hier:

Das User Objekt, das Sie bereits aus der Datenbank gelöst hält die Kennung (in diesem Fall id = 1) für Ihre Gruppenentität (diese ID kommt aus der groupId Spalte in Ihrer user Tabelle). Wenn Sie getGroup aufrufen, erstellt Doctrice nur einen Proxy für Ihre Entität Group und setzt id auf 1. Keine Notwendigkeit für Datenbankinteraktionen bisher.

Da Sie nichts anderes von Ihrer Group Entität anfordern, genügt in diesem einfachen Fall ein Proxy. Sie werden einen Unterschied feststellen, sobald Sie eine andere Eigenschaft von Ihrer Gruppenentität anfordern (jede andere direkte Eigenschaft (eine Spalte in Ihrer Gruppentabelle), aber die Kennung). Versuchen Sie beispielsweise, getName() auf Ihrer Gruppenentität aufzurufen. Diese Eigenschaft ist noch nicht geladen, so dass Doktrin die Zeile mit id = 1 aus der Tabelle group in Ihrer Datenbank abruft und alle Spalten als Eigenschaften (in diesem Fall gibt es nur eine) innerhalb Ihres Gruppenobjekts lädt und dann den Wert für zurückgibt der angeforderte Name

versuchen also einmal so:

$user->getGroup()->getName(); 

Und Ihre Ausgabe wird sehr unterschiedlich sein.

Ich hoffe, dass dies das Verhalten verständlicher macht.

+0

ja genau. Tatsächlich habe ich heute beschlossen, mir die von der Doktrin generierten Proxy-Klassen anzuschauen, und das konnte ich sehen. Ich habe die Lazy Loading Art falsch verstanden, indem ich schnell gelesen habe, zuerst dachte ich, dass das Aufrufen des Getters auf die Relation für die Doktrin ausreichte, um das Lazy Loading zu starten. In der Tat ist es notwendig, auf ein Attribut zuzugreifen. Danke für deine Erklärung – Bruce