Groups | Search | Server Info | Keyboard shortcuts | Login | Register


Groups > pl.comp.lang.php > #16233

Jak korzystać z Doctrine + PostgreSQL?

From Marek S <precz@spamowi.com>
Newsgroups pl.comp.lang.php
Subject Jak korzystać z Doctrine + PostgreSQL?
Date 2019-06-09 21:44 +0200
Organization ATMAN - ATM S.A.
Message-ID <qdjnif$e2l$1@node2.news.atman.pl> (permalink)

Show all headers | View raw


Witam,

Zabieram się do mojego pierwszego projektu w Symfony 4. Chcę zmienić 
swój sposób myślenia i zacząć korzystać z ORM -  w tym przypadku 
Doctrine. Póki co jestem na etapie postrzegania Doctrine jako rzucanie 
kłód pod nogi. To co było banalne w SQL, tu wymaga gimnastyki, a i tak 
kwiatki wychodzą. Zapewne czegoś nie wiem. Oto moje problemy:

Założenia.

Jest baza PostgreSQL. Dla testów tworzymy banalną tabelę, którą w SQL 
opisałbym jako:

CREATE TABLE public.task
(
     task_id BIGSERIAL,
     title varchar(255) NOT NULL,
     status boolean NOT NULL
)

Czynności

1. Próbowałem podejścia Database First aby nie marnować czasu na 
zmaganie się z ORMem. Niestety wszędzie piszą (zawsze nie wprost), że 
Doctrine przestaje to wspierać:
https://symfony.com/doc/4.0/doctrine/reverse_engineering.html
https://github.com/symfony/symfony-docs/issues/9172

"Symfony is a different project than Doctrine and we don't have any 
control over those decisions."

2. Ok, zatem pozostaje używać durnego narzędzia do kreowania tabel w 
postaci console make:entity. Wprowadzenie w ten sposób np. 100 pól 
bezbłędnie, graniczy z szaleństwem. A i tak narzędzie nie uwzględnia np. 
wartości domyślnych, nazwy klucza głównego i mnóstwa innych rzeczy więc 
ręcznie trzeba modyfikować klasę.

Jak sobie radzicie z tworzeniem tabel w bazie, aby było to przynajmniej 
tak proste, jak SQL i współgrało z Doctrine?

3. Na początek zbudowałem tabelkę jak w przykładzie powyżej, wpisując 
pole po polu w powyższym narzędziu. Oczywiście były potrzebne zmiany w 
klasie Task, bo kreator potrafi tylko zarys tabeli zbudować. Encja 
wygląda tak:


/**
  * @ORM\Entity(repositoryClass="App\Repository\TaskRepository")
  */
class Task {
     /**
      * @ORM\Id()
      * @ORM\GeneratedValue(strategy="IDENTITY")
      * @ORM\Column(type="bigint", name="task_id")
      */
     private $id;

     /**
      * @ORM\Column(type="string", length=255)
      */
     private $title;

     /**
      * @ORM\Column(type="boolean", options={"default": false})
      */
     private $status=false;


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


     public function getTitle(): ?string {
         return $this->title;
     }


     public function setTitle(string $title): self {
         $this->title = $title;

         return $this;
     }


     public function getStatus(): ?bool {
         return $this->status;
     }


     public function setStatus(?bool $status): self {
         $this->status = $status;

         return $this;
     }
}

Ręcznie musiałem zmienić:
      * @ORM\GeneratedValue(strategy="IDENTITY")
      * @ORM\Column(type="bigint", name="task_id")

i dopisać wartości domyślne pól poprzez zainicjowanie zmiennych 
prywatnych oraz uczynić to powtórnie zaklęciem 
@ORM\Column(type="boolean", options={"default": false})

Niesłychanie łatwo o błędy. Np. zmienię domyślną wartość w klasie, ale 
nie powtórzę tego w opcjach "default". Modyfikacji jest mnóstwo przy 
realnej wielkości tabeli.

Czy jest jakiś sposób usprawnienia kreowania tabeli?



3. Podczas rozmów tutaj, dowiedziałem się, że ORM zapewnia mi 
przenaszalność między bazami danych. Patrzę zatem w migrację i widzę:


$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 
'postgresql', 'Migration can only be executed safely on \'postgresql\'.');

         $this->addSql('CREATE TABLE task (task_id BIGSERIAL NOT NULL, 
title VARCHAR(255) NOT NULL, status BOOLEAN DEFAULT \'false\' NOT NULL, 
PRIMARY KEY(task_id))');

Mimo iż nie używam żadnych specjalnych typów pól, to powyższy kod nie 
wykona się dla baz innych niż PostgreSQL. Zatem jak jest z Doctrine? Da 
się przenosić struktury między typami baz, czy nie? Bo ja widzę, że nie.

4. Po wygenerowaniu pierwszej migracji, znalazłem kolejny kwiatek: żadna 
metoda "down" nie wykona się. Powstanie błąd SQL i koniec działania. Oto 
zawartość metody:

public function down(Schema $schema) : void
     {
         // this down() migration is auto-generated, please modify it to 
your needs
 
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 
'postgresql', 'Migration can only be executed safely on \'postgresql\'.');

         $this->addSql('CREATE SCHEMA public');
         $this->addSql('CREATE SCHEMA exclude');
         $this->addSql('CREATE SCHEMA exc');
         $this->addSql('DROP TABLE task');
     }

Nie wykona się linia:

$this->addSql('CREATE SCHEMA public');

...bo nie można tworzyć przestrzeni nazw, która jest już utworzona. Bez 
sensu zapis. Podobnie z kolejnymi przestrzeniami. DROP TABLE nie wykona 
się wskutek w/w błędu.

Dosłownie błąd na błędzie jest w Doctrine. Na Stacku ludzie też żalą się 
na to już od 2016 roku. Na DBALu iest issue od paru lat na ten temat.

Jak zacząć korzystać z Doctrine skoro już na wejściu katastrofa? Czy 
tylko ja tak mam?

-- 
Pozdrawiam,
Marek

Back to pl.comp.lang.php | Previous | NextNext in thread | Find similar


Thread

Jak korzystać z Doctrine + PostgreSQL? Marek S <precz@spamowi.com> - 2019-06-09 21:44 +0200
  Re: Jak korzystać z Doctrine + PostgreSQL? Marek S <precz@spamowi.com> - 2019-06-18 21:18 +0200

csiph-web