I have an entity which has a oneToMany relationship. The related entity has identity through the id of the first entity + another field. I tried to set cascade: ["persist"] on the first entity but when I'm trying to persist it it tells me that the related entities cannot be persisted and I first have to flush the first entity. But if I simply remove the cascade and flush the first entity it will give an exception saying that it won't persist because the related entities aren't persisted and i should set persist to cascade.
How to I solve this? The only solution that comes to mind is:
$relatedEntities = $entity1->getRelatedEntities();
$entity1->setRelatedEntities(new ArrayCollection());
$em->persist($entity1);
$em->flush($entity1);
$entity1->setRelatedEntities($relatedEntities);
$em->flush();
Is there any other way to do this?
As the error says you have to flush your first entity first. Then you flush the related entity. Some pseudo code:
$entity_one = new Something();
//Now set object values
$em->persist($entity_one);
$em->flush();
$entity_two = new SomethingElse();
//Now set object values (set the related/relation to the first entity)
$em->persist($entity_two);
$em->flush()
I'm not entirely sure you need to set the first entity to the second entity once you have flushed it. But you can find out very easy by trying it out ;)
Related
I have 2 Doctrine Entities with many-to-many relations. When I edit the first entity I want to be able to select the checkboxes that have the data from the 2nd entity to establish the joins for particular entry.
It works fine on creating a new Entry (using Array Collection), but when I want to edit an Entry - it adds the ones that I have selected without removing the previous choice (unchecking).
Which way would be the correct way to do that and how?
Remove all the Join table data for the Entry that is being updated,
then set the new data. (How can I remove it from the join table that
is not an Entity?)
Pass all the data from the 2nd Entity and remove
those that aren't checked (seems super-clumsy?)
Some other way I am not aware of?
I am not using Symfony, just Doctrine.
Doctrine makes working with the many-to-many associations quite easy. Your associations are stored into an ArrayCollection class that has some methods that can help you. First of all, check all the available methods for the ArrayCollection here (Doctrine API - ArrayCollection)
In your case, I'd use this approach: use the clear method on your ArrayCollection that contains the relationship with the 2nd entity and populate it again with the checked elements. After this, call the flush method on the entitymanager.
Another approach consists in filtering your collection (with the filter method) for getting a brand new ArrayCollection that contains only the elements that are checked. Like the first approach, associate this new collection to the relationship's ArrayCollection and call the flush method on the entitymanager.
With Doctrine 2, is it possible to add a new property to an entity to persist it in the entity manager, but NOT create a new column in the database ?
Purpose of that is to add a explain field to an entity and catch it with an event when UnitOfWork detects an update of one entity's value. (and perhaps send the content of the explain field by email, or log it, ...)
But I don't want to store this value in the database.
I have a story table and user table. The column userid in story table is a foreign key which refers the id in user table.
I have set the relationship is that a user may have many stories which is stored in story table. I have created the entities of both table.
But if try to persist operation only to story table it is asking the details for new user entry.
My objective is to add a new story with existing userId.
Am posting the error here:
A new entity was found through the relationship 'Story#_userId' that
was not configured to cascade persist operations for entity:
User#0000000038960c50000000008ea93852. 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\"}).
I set ManyToOne relationship in Story entity:
/**
* #ManyToOne(targetEntity="User", inversedBy = "_story" )
* #JoinColumns({
* #JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $_userId;
I checked the database schema and it shows relationship is set correctly. So I have done the story insertion process.
$user = new User();
$user->setUserId($id);
$story = new Story();
$story->setContent("....");
$story->setUserid($user);
$this->em->persist($story);
$this->em->flush();
You are probably persisting the story entity but not the user. If you have something like this:
$story = new Story();
$user = new User();
$story->setUser($user);
$em->persist($story);
$em->flush();
This will result in a fatal error, since you are persisting one entity, but through its relations, Doctrine finds another new entity. You have two options:
Call persist on both entities:
$story = new Story();
$user = new User();
$story->setUser($user);
$em->persist($story);
$em->persist($user);
$em->flush();
Or, set up cascading persist for the Story entity. Eg. if you are using annotation mapping, you would do something like
/**
* #ManyToOne(targetEntity="User", inversedBy="stories", cascade={"persist"})
*/
private $author;
The chapter 8. Working with associations details this.
K. Norbert's answer hits the spot, but there is something that might be unclear. At least it was unclear for me, who came to doctrine from SQL.
The thing is doctrine seem to remember which objects are already persisted. Whenever it finds new (not persisted yet) objects related to entity you want to persist - it yells with 'A new entity was found through the relationship ...' error. When you want to save new object (only one entity, without persisting related entities) you just need to make sure related entities are persisted already.
So:
$story = new Story();
$entityManager->find('User', $id);
$story->setUser($user);
$em->persist($story);
$em->flush();
does the trick. Because doctrine knows the user is persisted already and it doesn't need to do it anymore. Doctrine knows because we got the user from the database.
Dont you think you should set User rather than Userid for story
$user = new User();
$user->setUserId($id);
$story = new Story();
$story->setContent("....");
$story->setUser($user); //change here
$this->em->persist($story);
$this->em->flush();
I'm struggling to understand what you need, so I'm not sure if this will respond to your question.
As the story.user_id id a foreign key of user.id (which is a primary key), this can't be empty/null. So if, let's say, you have a php session, you should probably store your user id (or user name) in your session variables, and when you create a new record in the story table, use the user id from your session to populate the story.user_id attribute.
Hope it helps.
I would be helpful if you attach your entites.
But I suppose that it is simmilar problem to mine. You cannot define the #Id and #ManyToOne together in one field. You have to use separate fields for an #Id and for relation #ManyToOne.
If you have a new (not persisted yet) User entity, you have to persist User which have cascade={"persist"} or cascade={"all"} in field correspond to Story entity. You can store the Story entity only if User already exists and it is attached to Doctrine.
Hope it help.
I have 3 Entities Users, UserProfile and Staffs
The User profile is linked to Users table through user id
The Staff table is linked to userprofile using the userprofileid
Admin create the user profile and generate the registration no, username and password.
I want add a user record to the users table then add the user profile and then add the profile id to the staff table.
I want to persist three entities sequentialy
I tried to create an instance for the Users like
$this->userent->setUsername('xxx');
$this->em->persist($this->userent);
$this->em->flush();
then:
$this->profileent->setFirstname('xxx');
$this->em->persist($this->profileent);
$this->em->flush();
Basically a form is shared among three entities and I want to insert into three tables sequentially,
Updated
Apart from users entity i have a usertype entity linked to users...i want to persist only the foreign key. i have
setUserType(Usertype $userType) method an instance of the user_type entity in users
when i do
$this->userent = new Users();
$this->userent->setUserType($this->em->getRepository('\Campus\Entity\Usertype')->findByUserType("admin"))
i get the error
Argument 1 passed to Campus\Entity\Users::setUserType() must be an instance of Campus\Entity\Usertype, array given
if i pass the value of the array which is an instance of Usertype
i get an error saying need an array for the ArrayCollection..help please!!!
Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in D:\xampp\htdocs\zend\library\Doctrine\ORM\UnitOfWork.php on line 406 defined in D:\xampp\htdocs\zend\library\Doctrine\Common\Collections\ArrayCollection.php on line 46
Think less about the database, and more about your objects. That's the whole point of doctrine.
You want something like this:
<?php
// create some entities
$user = new Entity\User();
$user->setUsername('userman');
$profile = new Entity\UserProfile();
$profile->setFirstname('joe');
$profile->setLastname('smith');
$staff = new Entity\Staff();
$staff->setSomething('value-for-something');
// associate those entities together
$profile->setStaff($staff);
$user->setProfile($profile);
// assuming you have set up cascade={"persist"} on your associations
$this->em->persist($user);
// if you haven't set up cascade={"persist"}, you will need to call persist on each entity:
// $this->em->persist($profile);
// $this->em->persist($staff);
$em->flush();
So, the basic idea is you build up your objects, get them into Doctrine's Unit-of-Work (by calling persist() and maybe having some cascades set up), then write them all to the database in a single transaction by calling flush()
You can persist each entity, and then flush() one time at the end.
If you have relations between your entities, you can check the following annotation
cascade={"persist"}
"Cascades persist operations to the associated entities."
Have a look at the documentation here : http://docs.doctrine-project.org/en/2.0.x/reference/working-with-associations.html#transitive-persistence-cascade-operations
Is there a way to have something like this in doctrine:
class Entity {
/**
* #Column(name="related_entity_id")
*/
private $relatedEntityId;
/**
* #ManyToOne(targetEntity="RelatedEntitiy")
* #JoinColumn(name="related_entity_id", referencedColumnName="id")
*/
private $relatedEntity;
}
What I want to do I do something like this:
call Entity::setRelatedEntityId($someId), and persist the entity,
and have the entity return the related entity by calling Entity::getRelatedEntity().
The related entity is selected from a table which will be strictly limited and it will never dynamically grow at runtime, so there is a finite number of related entity ids.
At the time of creating a new Entity, I'd like to set the related entity id, but without having to fetch the whole related entity from the database.
As far as I could test this, it does not work, because if I set the relatedEntityId but not the relatedEntity, Doctrine automatically sets the related_entity_id column to null, since basically no relationship has been established.
I've tried to do something like this also:
remove the relatedEntityId property, and use
Entity::setRelatedEntity(new RelatedEntity($relEntId))
the constructor of the RelatedEntity will set the id, but not other values.
I do not want to persist the RelatedEntity (it's values are already set in the DB for the given $relEntId), but this time Doctrine signals an error at flush, because it has an unpersisted entity.
Basically, what I want to do is create a relationship without knowing anyhing but the Id of the related entity. If there is some other way this can be done, please share.
Thanks in advance
EDIT:
I've found a workaround. Since the RelatedEntities will be a limited set of immutable objects, I've done the following:
use the entityManager to find all RelatedEntities;
inject the list to the object that will be creating new Entities
when creating a new Entity, select one of the RelatedEntities from the list as its RelatedEntity
I'll leave the question open for a day or two, just in case somebody comes up with something better.
Use the entity proxy:
Entity::setRelatedEntity($entityManager->getReference('RelatedEntity', $relEntId))
I don't think this is supposed to work like how you described :)
The entity you add must be a Doctrine managed object, so that means you have to load it yourself first using the find() family of methods.
Based on my experience with Doctrine 2 further elaborated here http://ssmusoke.wordpress.com/2012/03/25/doctrine2-day-3-proxies-associations-relationships/
My approach is as follows:
a) Have only the $relatedEntity property
b) Add a getRelatedEntityId() function which returns the id value from $relatedEntity
c) Add a setRelatedEntityId() which sets the $relatedEntity object - you may need to load it from the database, saves you from polluting other layers when u only have the id of the related entity
d) Add getRelatedEntity() and setRelatedEntity() functions
BOTTOM LINE: You cannot have a property for the foreign key column and the mapped property as Doctrine gets confused