Doctrine many to one relationship persist operation - php

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.

Related

Saving Entity to specified table in Symfony

I am implementing horizontal sharding of my database in my Symfony application. I have a method to create a table based on the "template" Entity I've made. For example, my Entity "AnswerData" will be used to create tables such as "AnswerData_sourceA", "AnswerData_sourceB"... and so on that are exact same schemas as the entity-based "AnswerData". While I have the database tables created already, I'm not quite sure how to get Symfony and Doctrine to designate which table I want the Entity to be created/saved to.
For example:
$em = $this->getDoctrine()->getManager();
$answerData= new AnswerData();
$answerData->setData();
//Set other properties...
...
$em->persist($answerData);
$em->flush();
$em->clear();
The above would have Symfony/Doctrine save the Entity to "AnswerData" table, but I am not sure where/how to tell it to save it to the "AnswerData_sourceA" table. Should I be writing custom repository classes that handle this or can the above snippet be modified to manually set the table? Thank you for any advice!
If I understood you want to save to specified table. you need
/**
* #Entity
* #Table(name="AnswerData_sourceA")
*/
to specify that name like this.

Doctrine persist entity with related entities having former entity as key

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 ;)

Multiple entities persist doctrine2 Zend

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 it possible to get the ID of entity after persist and before Flush in Doctrine2?

I have the User Login Registration Page.
Now on the same Page i have one more Forms i.e UserInterests.
Now i have the PostPersist function which creates new UserProfile after User is Persisted
Now UserProfile is linked with User ID and UserInterests is linked with UserProfile ID
Now the client wants UserInterests on same User page but i have problem that UserProfile is not yet created. Now how can persist them. Is there any way
I don't think you can get the ID before flushing.
You could create an association between the models, that way Doctrine will take care of the id's when saving and you can retrieve your UserInterests with something like:
$user->getProfile()->getInterests();
So you would have your User model with a property that holds your UserProfile:
/**
* #OneToOne(targetEntity="UserProfile")
* #JoinColumn(name="profile_id", referencedColumnName="id")
**/
private $profile;
and your UserProfile class should have a property to hold the UserInterests model.
/**
* #OneToOne(targetEntity="UserInterests")
* #JoinColumn(name="interests_id", referencedColumnName="id")
**/
private $interests;
You can now create an empty $userProfile model (to link the others together, the actual filling can be done in your postPersist function) and a $userInterests model, associate them by
$interests = new UserInterests();
// create an empty UserProfile, and fill it in your PostPersist function,
// that way it can already be used to link the User and UserInterests
$profile = new UserProfile();
$profile->setInterests($interests);
$user->setProfile($profile);
Now Doctrine will fill in the ids when persisting and you don't need to worry about them.
More information here

Doctrine2 - using a foreign key column as a normal field

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

Categories