Doctrine Merge is not working as expected - php

I am getting the following json data from the client. JSON contains the parent and child details as below -
{
id : 1,
name : "Parent"
children : [
{ id : 1, name : "A" },
{ id : 2, name : "B" }
]
}
I am mapping these json data to Parent and Child Object.
Parent
class Parent{
/** #Id #Column(type="integer",name="order_no") #GeneratedValue * */
protected $id;
/**
* #OneToMany(targetEntity="Child",cascade={"merge"}, mappedBy="parent" )
*/
protected $children;
}
Child
class SalesOrderDetail extends BaseEntity {
/** #Id #Column(type="integer") #GeneratedValue * */
protected $id;
/**
* #ManyToOne(targetEntity="parent")
* #JoinColumn(name="parent_id")
*/
protected $salesOrder;
}
So far so good.
Now the issue is when I am trying to merge the parent
$em->merge($parent)
I am getting the following error. Note : The entire object parent and children are unmanaged object so I am trying to merge. If I just merge parent it works find but getting error if I am trying to save entire content of parent and its children.
Type: Doctrine\ORM\ORMInvalidArgumentException Message: Multiple
non-persisted new entities were found through the given association
graph: * A new entity was found through the relationship
'Ziletech\Database\Entity\Parent#itemSet' that was not configured to
cascade persist operations for entity:
Ziletech\Database\Entity\Child#0000000052218380000000007058b4a6. 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
'Ziletech\Database\Entity\Child#__toString()' to get a clue. * A new
entity was found through the relationship
'Ziletech\Database\Entity\Parent#itemSet' that was not configured to
cascade persist operations for entity:
Ziletech\Database\Entity\Child#0000000052218071000000007058b4a6. 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
'Ziletech\Database\Entity\Child#__toString()' to get a clue.

Related

Doctrine: how to describe manyToOne relation with composite key and update cascade?

I have a table that has composite primary key: id + est_date. And it has an entity:
class Parent
{
/**
* #ORM\Id
*/
private $id;
/**
* #ORM\Id
*/
private int $estDate;
...
}
Now I need to create a related table and its entity.
class Child
{
...
/**
* don't know what to write here
*/
private $parentId;
/**
* don't know what to write here
*/
private int $parentEstDate;
...
}
How to discribe relation ManyToOne (many "Child" entities may relate to 1 "Parent")? And the second issue is - "estDate" of the "Parent" may change. How to specify cascade update in "Child"?
Please don't write that doctrine doesn't recomment to use composite keys. I know that.
on the child-entity you would refer to the parent entity the same way as with single columns, essentially. Starting with
annotation version:
/**
* #ORM\ManyToOne(targetEntity=Parent::class)
*/
private ?Parent $parent;
since the child is the owning side, you have to provide join columns, as you have noticed. There is a badly documented annotation JoinColumns that allows to define multiple join columns. (Note for those using the attribute syntax instead: you should be able to have multiple #[JoinColumn(...)], without the JoinColumns-Wrapper)
annotation version:
/**
* #ORM\ManyToOne(targetEntity=Parent::class)
* #ORM\JoinColumns({
* #ORM\JoinColumn("parent_id", referencedColumnName="id"),
* #ORM\JoinColumn("parent_est_date", referencedColumnName="est_date")
* })
*/
private ?Parent $parent;
If you want to add the inverse side as well, you always reference the object property, not the columns when using mappedBy/inversedBy.
Generally with doctrine-orm: Your class/object should not care about columns, only about php stuff, doctrine should handle the rest. The annotations tell doctrine, how this converts to columns. So not every column will get its own property in this case.

Working with Doctrine array of enum and store it in a separate table

I'm currently building Entity model and one of my Doctrine Entities have ManyToMany relation with an external dictionary (like ENUM). So the entity field will be an Array of Enum.
I'm looking for a way to have it as an array field on my entity, but to store it as a separate DB table.
Would like to get any advice/links/etc.
The question is a bit out of context but..
A many to many is already an array (Iterator) in your entity.
You can create your own entity acting as a Many To Many and set the column as enum.
Finally, I've decided to create an Entity to store this relation. To make sure it will be deleted on unlinking from the parent entity, I've used the orphanRemoval=true option on the OneToMany relation side.
class Entity {
/**
* #ORM\OneToMany(targetEntity="EntityType", mappedBy="entity", orphanRemoval=true)
*/
protected $types;
}
class EntityType {
/**
* #ORM\ManyToOne(targetEntity="Entity")
*/
protected $entity;
/**
* #ORM\Column(type="MyEnum")
*/
protected MyEnum $type;
}

Merge is creating new record for children

Merge is creating not working for children #OneToMany
I am using Php Doctrine and I am using #OnToMany mapping with cascade all. I have a parent class SalesOrder and child class SalesOrderDetails.
Case 1 : Save - When I save new record sales order along with sales order details. It is working as expected.
Case 2 : Update - Here is the issue, I am merging the Sales Order which is fine however its inserting new records for its children SalesOrderDetail instead of updating it. Ideally it should it apply mergebut for children as well but its not.
As of now, I am getting the Sales Order Details by id from DB then change the properties of it. Ideally that should not be the case, mean if we set the id to unmanned object, it should update instead of creating new records.
Note:
1. Merge is working with parent object if it has the id value.
2. I am not adding new item here, I am just updating the existing recorded through merge.
SalesOrder.php
/**
* #Entity #Table(name="sales_orders")
* */
class SalesOrder extends BaseEntity {
/**
* #OneToMany(targetEntity="SalesOrderDetail",cascade="all", mappedBy="salesOrder" )
*/
protected $itemSet;
function __construct() {
$this->itemSet = new ArrayCollection();
}
}
SalesOrderDetail.php
/**
* #Entity #Table(name="sales_order_details")
* */
class SalesOrderDetail extends BaseEntity {
/** #Id #Column(type="integer") #GeneratedValue * */
protected $id;
/**
* #ManyToOne(targetEntity="SalesOrder")
* #JoinColumn(name="order_no", referencedColumnName="order_no")
*/
protected $salesOrder;
}
Debug Mode screen
If I use cascade={"merge"}
I am getting different error if I am using Cascades merge
Type: Doctrine\ORM\ORMInvalidArgumentException Message: Multiple
non-persisted new entities were found through the given association
graph: * A new entity was found through the relationship
'Ziletech\Database\Entity\SalesOrder#itemSet' that was not configured
to cascade persist operations for entity:
Ziletech\Database\Entity\SalesOrderDetail#0000000052218380000000007058b4a6.
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
'Ziletech\Database\Entity\SalesOrderDetail#__toString()' to get a
clue. * A new entity was found through the relationship
'Ziletech\Database\Entity\SalesOrder#itemSet' that was not configured
to cascade persist operations for entity:
Ziletech\Database\Entity\SalesOrderDetail#0000000052218071000000007058b4a6.
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
'Ziletech\Database\Entity\SalesOrderDetail#__toString()' to get a
clue.
You have a mistake in your mapping, cascade needs an array
/**
* #OneToMany(targetEntity="SalesOrderDetail", cascade={"all"}, mappedBy="salesOrder" )
*/
protected $itemSet;

Doctrine 2, error inserting in table with foreign key

I'm very new using Doctrine, is the first project I work with it and I'm having an error while I try to insert a new user.
The thing is I've got a class User with a foreign key Country and when I try to insert a user Doctrine also try to insert the country, the country already exists so PDO launch an integrity constraint violation and Doctrine a Doctrine\DBAL\DBALException.
I know the annotation cascade={"persist"} makes the country entity to be written in the db, without it, doctrine launch another error:
A new entity was found through the relationship 'User#country' that was not configured to cascade persist operations for entity: Country#0000000078b1861f00007f935266d9fe. 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 'Country#__toString()' to get a clue.
I've tried with all cascade options and only with persist and all the error above doesn't come up...
Is there something like cascade={"no-persist"} or something that tells doctrine the value of this attribute must be already inserted in table country???
Some code:
/**
* User
*
* #Table(name="user")
* #Entity
*/
class User {
...
/**
* #var Country
*
* #OneToOne(targetEntity="Country", cascade={"persist"})
* #JoinColumn(name="country", referencedColumnName="id")
*/
private $country
...
}
/**
* Country
*
* #Table(name="country")
* #Entity
*/
class Country {
...
/**
* #var integer
*
* #Column(name="id", type="integer")
* #Id
*/
private $id;
}
Any clue will be highly appreciated.
Thanks.
Put the cascade=persist back in.
You need to check the database to see if the country exists. Your insert with an existing country fails because the country object needs to be managed by the entity manager.
$country = $countryRepository->find($countryId);
if (!$country)
{
$country = new Country();
$entityManager->persist($country);
}
$user->setCountry($country);

Doctrine entities relationship

I have an entity Template and another one Request. Essentially, a template represents an html form, and a request will represent a collection of values which the form was filled with and a reference to the template id.
class Request {
/**
* #Id #Column(type="integer")
* #GeneratedValue
*/
private $id;
/**
* #ManyToOne(targetEntity="Template", cascade={"persist"})
* #JoinColumn(name="templateId", referencedColumnName="id", nullable=false)
*/
private $template;
...
What I am trying to achieve is that when Request is loaded from the DB then the object comes holding the relevant Template object with all its data. However, when requests are saved there is no need to save the template too... thus cascade={"persist"} should not be there.
1- Load all templates from db
2- User selects a template from a dropdown
3- Tmeplate shows on screen and the user fills it in
4- Request is saved
$request = new \entities\Request();
//template already exist in the db
$template = $this->templateRepository->fetchTemplate(1);
$request->template = $template;
...
$this->entityManager->persist($request);
$this->entityManager->flush();
Now the problem is when I use casade persist it saves another Template in the templates table. If I do not use cascade persist it errors:
Fatal error: Uncaught exception 'Doctrine\ORM\ORMInvalidArgumentException' with message 'A new entity was found through the relationship 'entities\Request#template' that was not configured to cascade persist operations for entity: entities\Template#00000000343e07770000000073e3b0ec. 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 'entities\Template#__toString()' to get a clue.' in C:\Development\wamp\www\vendor\doctrine\orm\lib\Doctrine\ORM\ORMInvalidArgumentException.php on line 59
What is the correct Doctrine relationship setting to achieve the desired behaviour?

Categories