php - Doctrine insert/update/modify sub entities on @OneToMany -


i have project based on symfony 2.6. has following structure:

customer->@onetomany->orders->@onetomany->domains->@onetomany->subdomains 

same in reverse order:

subdomains->@manytoone->domains->@manytoone->orders->@manytoone->customer 

doctrine creates additional pretty cool "magic" columns customer_id (in domains), order_id (in domains) , domain_id (in subdomains).

it think perfect, if these *_id cols filled ids of parent table. in case, not match time. tables customer , order, *_id cols filled properly.

my php code creates new domain entities. sets id, if record exists in db, , adds subdomains arraycollection.

here storeorder() method:

protected function storeorder(order $order, array $domains) {     if ($order->getdomains()->count() === 0) {         // insert         foreach ($domains $domain) {             $order->getdomains()->add($this->createdomainfromarray($domain));         }     } else {         // remove/add         $order->getdomains()->clear();         foreach ($domains $domain) {             $order->getdomains()->add($this->createdomainfromarray($domain));         }     }     //$updatedorder = $this->entitymanager->merge($order);     // starts commit process incl. transactions , prepared queries     $this->entitymanager->persist($order);     $this->entitymanager->flush();     // clear cached entities in em. speeds processing enormous     $this->entitymanager->clear();     $this->amountofdomains += count($domains); }  /**  * create domain object delivered data array  *  * @param array $data  * @return domain  */ protected function createdomainfromarray($data) {     $domain = new domain();     $domain->setordernumber($this->ordernumber);     $domain->fromarray(arrayutility::removesubentriesfromarray($data));     $this->addidtodomainiffoundindatabase($domain);     $this->addsubdomainstodomain($domain, $data['subdomain']);      return $domain; }  /**  * prevent duplicate domains in database have set id,  * if have found such domain in db  * @param domain $domain  */ protected function addidtodomainiffoundindatabase(domain $domain) {     /** @var domain|null $domainfromdatabase */     $domainfromdatabase = $this->finddomainbyseid($domain->getseid());     if ($domainfromdatabase instanceof domain) {         $domain->setid($domainfromdatabase->getid());     } }  /**  * find domain seid  *  * @param int $seid  * @return domain|null  */ protected function finddomainbyseid($seid) {     // not use empty, because findoneby can return null result     if (!isset($this->cache['domainfromdatabase']) || (is_object($this->cache['domainfromdatabase']) && $this->cache['domainfromdatabase']->getseid() !== $seid)) {         $this->cache['domainfromdatabase'] = $this->domainrepository->findoneby(array(             'seid' => $seid,             'ordernumber' => $this->ordernumber         ));     }     return $this->cache['domainfromdatabase']; }  /**  * add/override subdomains domain object  *  * @param domain $domain  * @param array $subdomains these subdomains request  */ protected function addsubdomainstodomain(domain $domain, array $subdomains) {     $first = true;     $this->amountofsubdomains += count($subdomains);     $domainfromdatabase = $this->finddomainbyseid($domain->getseid());     if ($domainfromdatabase instanceof domain) {         $subdomainsfromdatabase = $domainfromdatabase->getsubdomains();     } else {         $subdomainsfromdatabase = new arraycollection();     }      foreach ($subdomains $subdomain) {         // create new subdomain         $subdomainobject = new subdomain();         $subdomainobject->setordernumber($this->ordernumber);         $subdomainobject->fromarray($subdomain);          // add id subdomain, if have 1 in db         // it's not perfect, long can have equal records in subdomain table         // don't see chance change         if ($first) {             $subdomainfromdatabase = $subdomainsfromdatabase->first();             $first = false;         } else {             $subdomainfromdatabase = $subdomainsfromdatabase->next();         }         if ($subdomainfromdatabase instanceof subdomain) {             $subdomainobject->setid($subdomainfromdatabase->getid());         }          // add order customer         $domain->addsubdomain($subdomainobject);     } } 

here annotation order entity:

/**  * order -> domains  *  * @var arraycollection  * @orm\onetomany(targetentity="fqcn\domain", mappedby="order", cascade={"all"})  */ protected $domains; 

here annotations subdomain entity:

/**  * relation domain order  *  * @orm\manytoone(targetentity="fqcn\order", inversedby="domains")  */ protected $order = null;  /**  * domain -> subdomains  *  * @var arraycollection  * @orm\onetomany(targetentity="fqcn\subdomain", mappedby="domain", cascade={"all"})  */ protected $subdomains; 

if use flush(), *_id fields not filled. if call detach($order), fields filled properly, have second (duplicate) of $order in database. if use merge() works on insert, not if want update arraycollections.

what i'm doing wrong? how update arraycollections right way without removing , creating them again? how *_id field filled?

stefan

thank all. here solution:

i have added new function domain model, original subdomain object database:

public function getsubdomain($seid) {     foreach ($this->subdomains $subdomain) {         if ($subdomain->getseid() === $seid) {             return $subdomain;         }     } } 

in domainsynchronization-object decide between updated or new record:

$domainfromdatabase = $order->getdomain((int)$domain['seid']); if ($domainfromdatabase instanceof domain) {     // update     $this->updatedomainfromarray($domainfromdatabase, $domain); } else {     // insert     $order->getdomains()->add($this->createdomainfromarray($domain, $order)); 

}

and, @redbirdo mentioned, add domain object subdomains manually now:

protected function addsubdomainstodomain(domain $domain, array $subdomains) {     $this->amountofsubdomains += count($subdomains);     foreach ($subdomains $subdomain) {         $subdomainobject = $domain->getsubdomain((int)$subdomain['seid']);         if ($subdomainobject instanceof subdomain) {             // update             $subdomainobject->fromarray($subdomain);         } else {             // insert             $subdomainobject = new subdomain();             $subdomainobject->setdomain($domain);             $subdomainobject->setordernumber($this->ordernumber);             $subdomainobject->fromarray($subdomain);             $domain->addsubdomain($subdomainobject);         }     } } 

now don't need ->persist() or ->merge() anymore. it's enough call:

$this->entitymanager->flush(); 

any can see parent uids in subdomain table, too.

thank all


Comments

Popular posts from this blog

powershell Start-Process exit code -1073741502 when used with Credential from a windows service environment -

twig - Using Twigbridge in a Laravel 5.1 Package -

c# - LINQ join Entities from HashSet's, Join vs Dictionary vs HashSet performance -