2012-07-10 12 views
5

Nie rozumiem, dlaczego z niektórymi obiektami obiektu mogę ustawić identyfikator, a dla innych obiektów pojawia się błąd i mówi mi, że identyfikator nie może być pusty i zamiast tego muszę przekazać obiekt.Doctrine2, przekazać identyfikator lub obiekt?

np .:

$log = new Log(); 
$log->setTypeId(1); 
$log->setUserId(1); 
$entityManager->persist($log); 
$entityManager->flush(); 

Gdy próbuję powyższy kod otrzymuję błąd, który mówi: naruszenie więzów integralności: 1048 kolumna 'user_id' nie może być null. I muszę najpierw utworzyć obiekt tekstowy i De obiekt użytkownika, a ich pass:

$log->setType($TypeObject) 
$log->setUser($UserObject) 

Ale dla innych obiektów jednostki nie mam problemu z przypisaniem wartości bezpośrednio, to dlaczego?

To mój Podmiot Log:

<?php 
/** 
* @Entity 
* @Table(name="log") 
* @HasLifecycleCallbacks 
*/ 
class Log 
{ 
    /** 
    * @var type 
    * @Id 
    * @Column(type="integer") 
    * @GeneratedValue 
    */ 
    protected $id; 

    /** 
    * 
    * @var type 
    * @Column(type="integer") 
    */ 
    protected $user_id; 

    /** 
    * 
    * @var type 
    * @Column(type="integer") 
    */ 
    protected $type_id; 

    /** 
    * 
    * @var type 
    * @Column(type="datetime") 
    */ 
    protected $created; 

    /** 
    * 
    * @var type 
    * @ManyToOne(targetEntity="User", inversedBy="logs") 
    */ 
    protected $user; 

    /** 
    * 
    * @ManyToOne(targetEntity="Type", inversedBy="logs") 
    */ 
    protected $type; 

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

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

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

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

    public function setUserId($userId) 
    { 
     $this->user_id = $userId; 
    } 

    public function setTypeId($typeId) 
    { 
     $this->type_id = $typeId; 
    } 

    public function setCreated($created) 
    { 
     $this->created = $created; 
    } 

    public function setUser($user) 
    { 
     $this->user = $user; 
    } 

    public function setType($type) 
    { 
     $this->type = $type; 
    } 

    /** 
    * @PrePersist 
    */ 
    public function prePersist() 
    { 
     $this->setCreated(new DateTime()); 
    } 

} 
?> 
+1

Cieszę się, że pomogło. To dało mi znak 1K. woohoo. –

Odpowiedz

4

EDIT

znalazłem to oświadczenie na stronie internetowej Doctrine2. Jest to najlepsza praktyka, którą możesz zastosować podczas kodowania modeli.

Doctrine2 Best Practices

25,9. Nie zamapuj kluczy obcych na pola w jednostce

Klucz obcy nie ma żadnego znaczenia w modelu obiektowym. Klucze obce to sposób, w jaki relacyjna baza danych ustanawia relacje. Twój model obiektowy ustanawia relacje za pomocą odwołań do obiektów. Zatem mapowanie kluczy obcych obiektów do pola mocno przecieka szczegóły modelu relacyjnego do modelu obiektowego, coś, czego naprawdę nie powinni robić

EDYCJA

Doktryna robi odwzorowanie z obiektami do ich odpowiednich identyfikatorów.

To, co tu zrobiliście, jest nieco zbędne.

Zasadniczo powiedzieliście doktrynie to samo dwa razy.

Powiedziałeś, że ma on kolumnę "user_id" ORAZ że ma również obiekt użytkownika, który jest tym samym. Ale doktryna może już odgadnąć, że ta relacja będzie miała kolumnę user_id w oparciu o fakt, że klasa dziennika ma obiekt użytkownika w środku.

Należy po prostu wykonaj następujące czynności zamiast

<?php 
/** 
* @Entity 
* @Table(name="log") 
* @HasLifecycleCallbacks 
*/ 
class Log 
{ 
    /** 
    * @var type 
    * @Id 
    * @Column(type="integer") 
    * @GeneratedValue 
    */ 
    protected $id; 

    /** 
    * 
    * @var type 
    * @Column(type="datetime") 
    */ 
    protected $created; 

    /** 
    * 
    * @var type 
    * @ManyToOne(targetEntity="User", inversedBy="logs") 
    */ 
    protected $user; 

    /** 
    * 
    * @ManyToOne(targetEntity="Type", inversedBy="logs") 
    */ 
    protected $type; 

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

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

    public function setCreated($created) 
    { 
     $this->created = $created; 
    } 

    public function setUser($user) 
    { 
     $this->user = $user; 
    } 

    public function setType($type) 
    { 
     $this->type = $type; 
    } 

    /** 
    * @PrePersist 
    */ 
    public function prePersist() 
    { 
     $this->setCreated(new DateTime()); 
    } 

} 

Doctrine martwić user_id i type_id na jego własne. Nie musisz się o to martwić. W ten sposób możesz pracować z pełnymi obiektami, co ułatwia programowanie, zamiast martwić się o identyfikatory. Doctrine sobie z tym poradzi.

Jeśli WSZYSTKO, co masz, jest identyfikatorem, ponieważ to właśnie używasz na interfejsie, a następnie po prostu pobierz obiekt powiązany z tym identyfikatorem za pomocą Entitymanager.

$user = $em->getEntity('User', $idFromWeb); 
$log = new Log(); 
$log->setUser($user); 
+1

Pobieranie użytkownika $ z bazy danych wydaje się być obciążeniem. Jeśli wpis w dzienniku wymaga tylko UserId, dlaczego miałbyś pobrać cały rekord użytkownika. Czy istnieje sposób, aby tego uniknąć? –

+0

Mubix, masz rację. Ale podczas tego żądania prawdopodobnie już pobrałeś jednostkę użytkownika, aby uzyskać swoje preferencje lub zweryfikować informacje o haśle lub inne rzeczy. Doctrine2 pobiera także obiekt tylko raz. Jeśli wielokrotnie wywołasz metodę getEntity, Doctrine2 będzie zwracać ten sam obiekt bez powrotu do bazy danych. –

+1

A w scenariuszu, w którym wykonuje się operację wsadową i ładowanie wszystkich przywoływanych encji, aby Doctrine zaczepiła FK? Czy nie można tego obejść? Czuję się brudna, robiąc te wszystkie dodatkowe połączenia. Piszę surową deklarację PDO lub nie używam mapowania i po prostu ładuję tę encję przez repozytorium z kodu kontrolera. – ficuscr

20

Istniejąca odpowiedź nigdy nie pasowała do mnie.Istnieje wiele poprawnych scenariuszy, w których ładowanie obiektu tylko po to, by zdefiniować związek, mając już pod ręką FK, nie ma żadnego sensu.

Lepszym rozwiązaniem jest użycie metody EntityManager Doctrine o nazwie getRefrence.

Reference Proxies...

Sposób EntityManager # getReference ($ entityName, $ identyfikator) pozwala uzyskać odniesienie do podmiotu, dla którego identyfikator jest znana, bez załadunku, że podmiot z bazy danych. Jest to użyteczne, na przykład jako poprawa wydajności, gdy chcesz ustanowić skojarzenie z jednostką, dla której masz identyfikator. Można po prostu to zrobić:

<?php 
    // $em instanceof EntityManager, $cart instanceof MyProject\Model\Cart 
    // $itemId comes from somewhere, probably a request parameter 
    $item = $em->getReference(\MyProject\Model\Item::class, $itemId); 
    $cart->addItem($item); 

Może to nie był dostępny, gdy kwestia ta została po raz pierwszy pisał - nie wiem.

+3

Nie wiedziałem o tej metodzie i wygląda dokładnie to, o co proszony jest oryginalny plakat. –

+0

To jest idealne. Czy to nowa funkcja? – pagliuca

+0

Próbowałem to ustalić i nie jestem pewien, kiedy to stało się dostępne (2.0>?). Został dodany w zeszłym roku. – ficuscr

Powiązane problemy