Doctrine 2 – not configured to cascade persist operations for entity

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Joacim
Člen | 229
+
0
-

Zdravím,
už dva dny mám takový větší problém s Doctrine 2 a nevím si rady.

Pokud se snažím uložit schůzku a použiji $this->em->persist($meeting); nahlásí mě to tuto chybu:

Doctrine\ORM\ORMInvalidArgumentException

A new entity was found through the relationship 'App\Model\Entities\Meeting#created_by' that was not configured to cascade persist operations for entity: App\Model\Entities\User@000000004b72e2f900007f852866c8dc. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'App\Model\Entities\User#__toString()' to get a clue.

pokud přidám v entite meeting ke created_by , cascade={"persist"} nahlásí mě to toto

Doctrine\ORM\ORMInvalidArgumentException

A new entity was found through the relationship 'App\Model\Entities\User#role' that was not configured to cascade persist operations for entity: Kdyby\GeneratedProxy\__CG__\App\Model\Entities\AclRole@000000000bd2af5c00007f8518be642e. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'App\Model\Entities\AclRole#__toString()' to get a clue.

a tak stále dokola.

pokud použiji $this->em->merge($meeting);, schůzka se uloží.
Bohužel po merge mi vložená entita nevrátí její ID (lastInserId dané entity co jsem vložil).

Proto potřebuji použít persist. Předtím když jsem měl menší DB schéma jsem vše ukládal přes persist a neměl jsem žádný problém.

Pokud mám entitu která se odkazuje na další entity (Meeting MeetingLog – 1:N) a chci vložit ke schůzce log a ukládám schůzku přes merge, flush a ne persist, flush, tzn vytvořím schůzku novou a hned k ní vytvořím log, nebo k již existující schůzce přidám log a k logu hned přidám soubor.

    public function addLog(NS_User $creator, $values) {
    $created_by = $creator->identity->entity;
    $this->em->clear();
    $log = new MeetingLog();
    $log->name = $values->name;
    $log->description = $values->description;
    $log->created = new DateTime();
    $log->created_by = $created_by;
    $log->meeting = $this->getMeeting($values->mid);
    $log->log_type = $this->getMeetingLogType(1);

    $this->em->merge($log);

    //Add file
    if ($values->file_1->name != NULL) {
        $file = new MeetingFile();
        $file->name = $values->file_1->getName();
        $file->revision = 1.0;
        $file->size = $values->file_1->getSize();
        $file->content_type = $values->file_1->getContentType();
        $file->sanitized_name = $values->file_1->getSanitizedName();
        $file->created = new DateTime();
        $file->meeting = $this->getMeeting($values->mid);
        $file->created_by = $created_by;
        $file->log = $log;

        $this->em->merge($file);
        $this->em->flush();

        $this->file_facade->addFile('meetings', $values->mid, $values->file_1);
    }

    // Store data to Db tables
    $this->em->flush();
}

Dostanu také: IMG , pokud všude kde mi doctrine hlásí dám ,cascade={"persist"} (i manytoone) dostanu hlášku IMG mezi User MeetingLog a MeetingFile mám tyto závislosti DB

Entity

class Meeting extends BaseEntity {
    /* ------------------------- Association Mapping ------------------------ */
    /**
     * Sloupec s asociací na Entitu User (Uživatele, který danou schůzku vytvořil).
     * -- 5.1. Many-To-One, Unidirectional
     * @ORM\ManyToOne(targetEntity="User", cascade={"persist"})
     * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $created_by;

    /**
     * Sloupec s asociací na Entitu MeetingType (Typ Schůzky).
     * @ORM\ManyToOne(targetEntity="MeetingType", inversedBy="ac_type")
     * @ORM\JoinColumn(name="type_id", referencedColumnName="id")
     *
     */
    protected $type;

    /**
     * Sloupec s asociací na Entitu MeetingStatus (Stav (status) dané schůzky).
     * @ORM\ManyToOne(targetEntity="MeetingStatus", inversedBy="ac_meeting")
     * @ORM\JoinColumn(name="status_id", referencedColumnName="id")
     *
     */
    protected $status;

    /**
     * Sloupec s asociací na Entitu TmC.
     * @ORM\ManyToOne(targetEntity="TmC", inversedBy="ac_meeting_c")
     * @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
     *
     */
    protected $customer;

    /**
     * Sloupec s asociací M:N na Entitu TmPN přes mapovací tabulku typu M:N (meeting_pn_map) (Všechny PN z TM), k dané schůzce
     *
     * @ORM\ManyToMany(targetEntity="TmPN")
     * @ORM\JoinTable(name="meeting_pn_map",
     *      joinColumns={@ORM\JoinColumn(name="meeting_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="pn_id", referencedColumnName="id")}
     *      )
     * @ORM\OrderBy({"pn" = "ASC"})
     */
    protected $ac_pn;

    /**
     * Sloupec s asociací M:N na Entitu User přes mapovací tabulku typu M:N (meeting_user_map) všinchni uživatele přizvaní (obeznámení) o dané schůzce
     *
     * @ORM\ManyToMany(targetEntity="User")
     * @ORM\JoinTable(name="meeting_user_map",
     *      joinColumns={@ORM\JoinColumn(name="meeting_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}
     *      )
     * @ORM\OrderBy({"last_name" = "ASC"})
     */
    protected $ac_invited;

    /**
     * Namapovaná vazba schůzky 1:N na tabulku všech souborů k dané schůzce.
     * @ORM\OneToMany(targetEntity="MeetingFile", mappedBy="meeting")
     * @ORM\OrderBy({"name" = "ASC"})
     */
    protected $ac_meeting_file;

    /**
     * Namapovaná vazba schůzky 1:N na tabulku všech logů k dané schůzce.
     * @ORM\OneToMany(targetEntity="MeetingLog", mappedBy="meeting")
     * @ORM\OrderBy({"created" = "DESC"})
     */
    protected $ac_meeting_log;

    /* --------------------------- Entity Methods --------------------------- */

    /** Konstruktor s inicializací objektů pro vazby mezi entitami. */
    public function __construct() {
        parent::__construct();
        $this->ac_pn = new ArrayCollection();
        $this->ac_invited = new ArrayCollection();
        $this->ac_meeting_file = new ArrayCollection();
        $this->ac_meeting_log = new ArrayCollection();
    }

    public function addPartNumber(Tm1PartNumber $pn) {
        $this->ac_pn[] = $pn;
    }

    public function addInvited(App\Model\Entities\User $invited) {
        $this->ac_invited[] = $invited;
    }
}
class MeetingFile extends BaseEntity {
    /* ------------------------- Association Mapping ------------------------ */
    /**
     * Sloupec s asociací na Entitu Meeting (k jaké schůzce se soubor váže).
     * @ORM\ManyToOne(targetEntity="Meeting")
     * @ORM\JoinColumn(name="meeting_id", referencedColumnName="id")
     */
    protected $meeting;

    /**
     * Sloupec s asociací na Entitu User (Uživatel, který daný soubor vytvořil)
     * -- 5.1. Many-To-One, Unidirectional
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $created_by;

    /**
     * Sloupec s asociací na Entitu MeetingLog 1:1 (Soubor muže být vázán vždy na jeden log)
     *
     * @ORM\OneToOne(targetEntity="MeetingLog", inversedBy="file", cascade={"persist"})
     * @ORM\JoinColumn(name="log_id", referencedColumnName="id")
     */
    protected $log;
}
class MeetingLog extends BaseEntity {
    /* ------------------------- Association Mapping ------------------------ */
    /**
     * Sloupec Typ Logu.
     * @ORM\ManyToOne(targetEntity="MeetingLogType", inversedBy="ac_meeting_log")
     * @ORM\JoinColumn(name="log_type_id", referencedColumnName="id")
     */
    protected $log_type;

    /**
     * Sloupec s asociací na Entitu User (Uživatel, který daný log vytvořil)
     * -- 5.1. Many-To-One, Unidirectional
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
     */
    protected $created_by;

    /**
     * Sloupec s asociací na Entitu Meeting (k jaké schůzce se log váže).
     * @ORM\ManyToOne(targetEntity="Meeting", inversedBy="ac_meeting_log")
     * @ORM\JoinColumn(name="meeting_id", referencedColumnName="id")
     */
    protected $meeting;
}
Joacim
Člen | 229
+
0
-
class User extends BaseEntity {
    /* ------------------------- Association Mapping ------------------------ */
    /**
     * Sloupec role uživatele.
     * @ORM\ManyToOne(targetEntity="AclRole", inversedBy="ac_user")
     * @ORM\JoinColumn(name="role_id", referencedColumnName="id")
     *
     */
    protected $role;

    /**
     * Sloupec role uživatele.
     * @ORM\ManyToOne(targetEntity="TmRole", inversedBy="ac_user")
     * @ORM\JoinColumn(name="tm_role_id", referencedColumnName="id")
     *
     */
    protected $tm_role;

    /**
     * Namapovaná vazba uživatele 1:N na tabulku logů příhlášení.
     * @ORM\OneToMany(targetEntity="UserLoginInfo", mappedBy="user")
     */
    protected $ac_login_info;

    /**
     * Namapovaná vazba uživatele 1:N na tabulku s nastavením účtu uživatele.
     * @ORM\OneToMany(targetEntity="UserAttribute", mappedBy="user")
     */
    protected $ac_user_attribute;

    /* --------------------------- Entity Methods --------------------------- */

    /** Konstruktor s inicializací objektů pro vazby mezi entitami. */
    public function __construct() {
        parent::__construct();
        $this->ac_login_info = new ArrayCollection();
        $this->ac_user_attribute = new ArrayCollection();
    }

    /**
     * Přidá informace o uživatelově přihlášení (UserLoginInfo)
     * @param \App\Model\Entities\UserLoginInfo $info
     */
    public function addLoginInfo(UserLoginInfo $info) {
        $this->ac_login_info[] = $info;
        $info->user = $this;
    }

    /**
     * Přidá uživatelský atribut (UserAttribute)
     * @param \App\Model\Entities\UserAttribute $attribute
     */
    public function addUserAttribute(UserAttribute $attribute) {
        $this->ac_user_attribute[] = $attribute;
        $attribute->user = $this;
    }
}

Entita User (přesáhnul jsem u článku max povolený počet znaku 10000), proto komentář.

David Matějka
Moderator | 6445
+
0
-

Je problem v tom, ze User-a davas do identity a tam se serializuje a pak unserializuje. To zpusobuje problemy a kdyz nevis, jak s tim spravne zachazet, tak je lepsi se tomu vyhnout.

Pouzij https://github.com/…ity-doctrine

Joacim
Člen | 229
+
0
-

David Matějka napsal(a):

Je problem v tom, ze User-a davas do identity a tam se serializuje a pak unserializuje. To zpusobuje problemy a kdyz nevis, jak s tim spravne zachazet, tak je lepsi se tomu vyhnout.

Pouzij https://github.com/…ity-doctrine

Stačí tedy dát do Nette User pouze ID z DB a pak si načítat danou entitu a její asociace ? Bohužel je ten projekt tak velký, že používat a implementovat další udělátka nemám čas (min další 2 měsíce), a tohle mě docela solidně zavařilo. Popravdě mě nenapadlo že by zrovna tohle mohlo dělat problémy, hold chybama se člověk učí.

Každopádně nette-identity-doctrine vypadá užitečně a kouknu na něj, ted by mě ale zajímalo jak z této situace ven, zda stačí skutečně do identity dát pouze ID a entitu vyjmout

Editoval Joacim (14. 4. 2016 18:16)

Aurielle
Člen | 1281
+
0
-

Implementace zmíněného rozšíření je práce asi tak na pět minut, zvlášť, když už v identitě svoji entitu User očekáváš.

Joacim
Člen | 229
+
0
-

Aurielle napsal(a):

Implementace zmíněného rozšíření je práce asi tak na pět minut, zvlášť, když už v identitě svoji entitu User očekáváš.

Ano pravda, včera jsem na to koukal, přesto mě zajímalo zda je problém v tom že jsem ukládal UserEntitu aktuálně přihlášeného uživatele do Nette User → identity->entity, to jsem celé předělal ted mám jen:

Nette\Security\Identity #0208
id private => 1
roles private => array (1)
0 => "admin"
data private => array (3)
email => "admin"
login_id => 103

A přesto dostávám stále stejné hlášky, cache jsem promazal a entitu MeetingLog jsem přidal persist

/**
    * Sloupec s asociací na Entitu User (Uživatel, který daný log vytvořil)
    * -- 5.1. Many-To-One, Unidirectional
    * @ORM\ManyToOne(targetEntity="User", cascade={"persist"})
    * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
    */
   protected $created_by;

a dostanu hlášku

Notice

Undefined index: 000000001c2bade800007f8548f0ec08

// File: .../doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:2917

Editoval Joacim (15. 4. 2016 11:10)

David Matějka
Moderator | 6445
+
0
-

protoze volas

$this->em->clear();

proc to delas?

Joacim
Člen | 229
+
0
-

David Matějka napsal(a):

protoze volas

$this->em->clear();

proc to delas?

moje chyba, to byl pokus o napravu, který jsem u stejné chyby našel na stackowerflow.

Tak jsem přidal cascade persist (k undirectionl asociaci) , odddělal entitu z user identity a místo merge dal persist, oddělal clear a zdá se že už to funguje jak má