I have a form that shows entity:
class Event
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\OneToMany(targetEntity="EventAttendee", mappedBy="event", cascade={"all"})
*/
private $attendees;
}
and a collection within it:
class EventAttendee
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="Event", inversedBy="attendees")
* #ORM\JoinColumn(name="event_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $event;
/**
*
* #ORM\OneToOne(targetEntity="Employee")
* #ORM\JoinColumn(name="employee_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $employee;
}
If I delete an employee from the collection and add it again, I'm getting integrity constraint violation. This is because Doctrine's UnitOfWork first executes Inserts and then Deletes. Therefore, when it inserts a new record db still has the old one with the same employee.
Doctrine2 developers did not provide any working solution for Symfony2 users (here is the thread: http://www.doctrine-project.org/jira/browse/DDC-601).
And thus, I'm asking the question here: is it anyhow possible to avoid this issue?
EDIT:
My current workaround is:
find all not-persisted colletion items ready to insert
remove them from the collection and save to a variable
remove all the items that were really deleted in the form
call flush()
add all the items for insert back to the collection
call flush()
This works for me, however doesn't look good. Maybe someone has a better solution.
Related
I've got myself an entity
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="position", type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $position;
The Id is the primary key but I'll sort the array with position. I want to make functions to swap 2 of the items when sorting or move them up and down.
How can I make a constructor that will increment each new object I create automatically?
I've tried:
/**
* Constructor
*/
public function __construct()
{
$this->position = $this->id+1;
}
But the Id is assigned after persisting the object so each one has position set to 1. Do I need to use Life Cycle Callbacks?
Lifecycle callbacks could work to do what you want but you have to be aware that if you modify an entity after flushing to the database you're gonna have to flush again to save the new information.
i have a strange problem when trying to render entity in symfony2 easyadminBundle i got a blank screen without any errors,
when trying to list entity 'Ads' that has many-to-one relation-ship with entity 'pages' ,where page contains many ads., however if i modified the action parameter in the url to be &action=new instead of &action=list it shows the form but after saving it giving me the same blank screen!
My Pages Entity :
/**
* #var string
*
* #ORM\Column(name="page_name", type="string", length=30, nullable=true)
*/
private $pageName;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/*#ORM\OneToMany(targetEntity="Ads", mappedBy="pages")
*
*/
protected $ads;
public function __construct()
{
$this->ads = new ArrayCollection();
}
}
Ads Entity:
/**
* Ads
*
* #ORM\Table(name="ads")
* #ORM\Entity
*/
class Ads
{
/**
* #var integer
*
* #ORM\Column(name="page_id", type="integer", nullable=false)
*/
private $page_id ;
/**
* #var string
*
* #ORM\Column(name="ad_text", type="text", nullable=false)
*/
private $adText;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Pages", inversedBy="ads")
* #ORM\JoinColumn(name="page_id", referencedColumnName="id")
*/
private $page_ad;
}
Your configuration looks "not complicated", so it should work as expected. The "blank page" error is really strange. We render the data with try...catch to avoid any issue when we cannot access the information. Besides, we also catch the exceptions to display customized error pages.
Can you see any error message in your dev.log file?
You could also do the following. Create the simplest possible configuration for the list view of the Ads entity as follows:
easy_admin:
entities:
Ads:
list:
fields: ['id']
If this work, try adding more fields one by one until you find the error.
I can't figure it out..
Why I haven't access to Country table?
countryName should show Great Britain but it doesn't.
This is my dump($User):
My my piece of code of User entity:
/**
*
* #ORM\ManyToOne(targetEntity="Dashboard\MainBundle\Entity\Country", cascade={"persist"})
* #ORM\JoinColumn(name="country_id", referencedColumnName="id", nullable=true)
*
*/
private $countryId;
And my piece of code of Country Entity:
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
Depending on how you get the user maybe it is a lazy load that you are using which will get the country only if you call the getter explicitly, to always get a country with the user try :
/**
*
* #ORM\ManyToOne(targetEntity="Dashboard\MainBundle\Entity\Country", cascade={"persist"}, fetch="EAGER")
* #ORM\JoinColumn(name="country_id", referencedColumnName="id", nullable=true)
*
*/
private $countryId;
But still we need to know how you are getting the user the lazy load may override the fetch eager.
Your Country object is now only a Proxy object - dump function don't call a Doctrine to get a related object. Try before dump get your object for example:
dump($User->getCountry()):
dump($User);
OR try left join you Country in QueryBuilder
OR find a information about lazy load in Doctrine2 here
There are three entities: Customer, Messages, Attachments.
The relationship between these entities is straight forward: A customer can have many messages and a message can have many attachments. Both relations are "one-to-many".
I told doctrine to be lazy when loading the messages for the Customer entity. So $customer->getMessages() results in an additional SQL statement. That's fine.
But I also defined an "EAGER" loading for the attachments for the Message entity.
Now I would have expected that the messages I get by calling $customer->getMessages() are already loaded with all their attachments. But $message->getAttachments() still causes one SQL statement per message.
Is this behavior expected?
Just for reference, excepts from my classes:
Customer.php
class Customer
{
/**
* #ORM\OneToMany(targetEntity="Message", mappedBy="customer")
* #ORM\OrderBy({"createdOn" = "DESC"})
*/
private $messages;
Message.php
class Message
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="messages")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
**/
private $customer;
/**
* #ORM\OneToMany(targetEntity="Attachment", mappedBy="message", fetch="EAGER")
**/
private $attachments;
Attachment.php:
class Attachment
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Message", inversedBy="attachments")
* #ORM\JoinColumn(name="message_id", referencedColumnName="id")
**/
private $message;
It sounds like expected behavior to me. The doctrine documentation seems to imply that eager fetching is only one level deep.
According to the docs:
Whenever you query for an entity that has persistent associations and
these associations are mapped as EAGER, they will automatically be
loaded together with the entity being queried and is thus immediately
available to your application.
http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#by-eager-loading
The entity being queried in your case is customer and customer has eager on messages so messages are populated. Messages, however are not the object being queried, so attachments do not get loaded.
the correct code example might be like the following:
NOTE: fetch message with lazy loading, i.e. get messages with additional query proactively; as long as the messages are fetched from database, the corresponding attachments referenced to each message will be loaded automatically.
Customer
class Customer
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Message", mappedBy="customer", fetch="LAZY")
* #ORM\OrderBy({"createdOn" = "DESC"})
*/
private $messages;
Message
class Message
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="messages")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customer;
/**
* #ORM\OneToMany(targetEntity="Attchment", mappedBy="message", fetch="EAGER")
*/
private $attachments;
Attachment
class Attachment
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToONe(targetEntity="Message", inversedBy="attachments")
* #ORM\JoinColumn(name="message_id", referencedColumnName="id")
*/
private $message;
I have a system that took form information detailing a project, added it to a project table and is meant to add an entry into an assigned projects table to associate user with project (point of this is allowing multiple users for each project). Anyway I got this working without foreign keys, struggled to add them but eventually got them.
Unfortunately this additional has caused this error 'SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'projectId' cannot be null' whenever something is added to the assignedProjects table.
So my question is, have I missed something in my codes?
The code to add a new row to assignedProjects:
$assignedProject = new AssignedProjects();
$assignedProject->setProjectId($project->getId());
$assignedProject->setUserId($user[0]['id']);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($assignedProject);
$em->flush();
The code for the assignProjects entity:
class AssignedProjects
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer $projectId
*
* #ORM\Column(name="projectId", type="integer")
*/
private $projectId;
/**
* #ORM\ManyToOne(targetEntity="Projects", inversedBy="assignment")
* #ORM\JoinColumn(name="projectId", referencedColumnName="id")
*/
private $project;
/**
* #var integer $UserId
*
* #ORM\Column(name="userId", type="integer")
*/
private $userId;
/**
* #ORM\ManyToOne(targetEntity="Dev\UserBundle\Entity\User", inversedBy="assignment")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
(followed by the usual getters and setters)
and the project tables entity is:
class Projects
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $projectName
*
* #ORM\Column(name="projectName", type="string", length=255)
*/
private $projectName;
/**
* #ORM\OneToMany(targetEntity="AssignedProjects", mappedBy="project")
*/
protected $assignment;
Any help would be much appreciated!
Either you use the ProjectId and UserId columns and manage the relationship manually (not recommended) or you use the doctrine relationships(recommended), but don´t do both things. If you go for the second option, don´t include the projectId and userId columns, they are automatically created for you by doctrine. So, your AssignedProjects class should be:
class AssignedProjects {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id * #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Projects", inversedBy="assignment")
* #ORM\JoinColumn(name="projectId", referencedColumnName="id")
*/
private $project;
/**
* #ORM\ManyToOne(targetEntity="Dev\UserBundle\Entity\User", inversedBy="assignment")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
and in your controller you would do:
$assignedProject = new AssignedProjects();
$assignedProject->setProject($project);
$assignedProject->setUser($user[0]);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($assignedProject);
$em->flush();
Note that I am setting the Project and User fields, not the ids
By the way, unless you need to save extra data about this project assignement (things like the date or similar), you can declare a direct ManyToMany relationship between User and Project and do away with this class, Doctrine would generate the needed table by itself
With Doctrine2, you don't have to declare the foreign key (projectId) but only the association (project). So you can delete $projectId property, as well as setProjectId ans getProjectId methods. Same fix for $user...
Instead, you will use setProject like that :
$assignedProject = new AssignedProjects();
$assignedProject->setProject($project);
$assignedProject->setUser($user[0]);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($assignedProject);
$em->flush();
Have a look to Doctrine2 documentation, it will help you, for sure !
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.1/reference/association-mapping.html