I have a question similar to this one.
I need a relation one-to-one through composite key, is it possible? I've read about this but it's referred to one-to-many relation
class Header{
/**
*
* #ORM\Id
* #ORM\Column(name="UH1", type="integer", nullable=false)
*/
protected $key1;
/**
*
* #ORM\Id
* #ORM\Column(name="UH2", type="integer", nullable=false)
*/
protected $key2;
/**
* #ORM\OneToOne(targetEntity="Detail", mappedBy="header")
*/
protected $detail;
}
class Detail{
/**
*
* #ORM\Id
* #ORM\Column(name="UD1", type="integer", nullable=false)
*/
protected $key1;
/**
*
* #ORM\Id
* #ORM\Column(name="UD2", type="integer", nullable=false)
*/
protected $key2;
/**
* #ORM\OneToOne(targetEntity="Header", inversedBy="detail")
*/
protected $header;
}
I mean there are two columns as Id per entity... do i need to add the joincolumn ?
You need to use the JoinColumns annotation that allows to define an array of JoinColumn annotations to handle such cases for ManyToOne or OneToOne associations.
With the following entities:
AppBundle\Entity\A.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class A
{
/**
* #ORM\Id
* #ORM\Column(name="key1", type="integer", nullable=false)
*/
private $key1;
/**
* #ORM\Id
* #ORM\Column(name="key2", type="integer", nullable=false)
*/
private $key2;
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\B", mappedBy="a")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="key1", referencedColumnName="key1"),
* #ORM\JoinColumn(name="key2", referencedColumnName="key2"),
* )
*/
private $b;
}
AppBundle\Entity\B.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class B
{
/**
* #ORM\Id
* #ORM\Column(name="key1", type="integer", nullable=false)
*/
private $key1;
/**
* #ORM\Id
* #ORM\Column(name="key2", type="integer", nullable=false)
*/
private $key2;
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\A", inversedBy="b")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="key1", referencedColumnName="key1"),
* #ORM\JoinColumn(name="key2", referencedColumnName="key2"),
* )
*/
private $a;
}
I could achieve the desired behaviour. When asked for a schema update, Doctrine outputs:
CREATE TABLE a (key1 INT NOT NULL, key2 INT NOT NULL, UNIQUE INDEX b_uniq (key1, key2), PRIMARY KEY(key1, key2)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE b (key1 INT NOT NULL, key2 INT NOT NULL, UNIQUE INDEX a_uniq (key1, key2), PRIMARY KEY(key1, key2)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE a ADD CONSTRAINT FK_E8B7BE432C5C6450B55535EA FOREIGN KEY (key1, key2) REFERENCES b (key1, key2);
ALTER TABLE b ADD CONSTRAINT FK_71BEEFF92C5C6450B55535EA FOREIGN KEY (key1, key2) REFERENCES a (key1, key2);
Related
I have project that is migrate to Symfony, that project have multiple tables,and also some tables are migrated to ORM, but now i need to incert/update from Symfony to table that have Entity but not managed by ORM. Problem consist in not null columns that require some value and in Entity I cannot define that value because of table relations.
It posible to edit MySql query before they submited to Database.
For example i have Entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="p_user")
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User
{
/**
* #var int
*
* #ORM\Column(name="user_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string|null
*
* #ORM\Column(name="name", type="string", length=55, nullable=true)
*/
private $name;
/**
* #var Permission
*
* #ORM\ManyToOne(targetEntity="Permission", inversedBy="user", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="permission_id", referencedColumnName="permission_id", onDelete="CASCADE")
*/
private $permission;
}
permission_id can be null but in database is not null with default value 0, same for name but with default value ''.
That mean when I make flush, ORM execute INSERT INTO p_user (name, permission_id) VALUES ('name', null), but I want also to execute INSERT INTO p_user (name) VALUES ('name').
It's possible to do that I wanted.
To achieve this you can provide default values.
private $permission = 0;
private $name = '';
I have two entities:
/**
* Course
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="AppBundle\Entity\Repository\CourseRepository")
*/
class Course
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \Doctrine\Common\Collections\ArrayCollection()
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\TimeTableEntry", mappedBy="course", cascade={"remove"}, orphanRemoval=true)
*
*/
private $timeTableEntries;
/**
* #var boolean
*
* #ORM\Column(name="enabled", type="boolean", nullable=true)
*/
private $enabled;
and
/**
* TimeTableEntry
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="AppBundle\Entity\Repository\TimeTableEntryRepository")
*/
class TimeTableEntry
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \Doctrine\Common\Collections\ArrayCollection()
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Course", inversedBy="timeTableEntries", cascade={"ALL"})
* #ORM\JoinColumn(name="course_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
private $course;
As you can see I tried with cascade={"ALL"}, onDelete="CASCADE" and orphanRemoval=true.
When I want to delete the Course Entity I get the error message:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or
update a parent row: a foreign key constraint fails
(edutalk.teaching_event, CONSTRAINT FK_F2B1088B57042871 FOREIGN
KEY (time_table_entry_id) REFERENCES time_table_entry (id))
What can I try to resolve this?
I cannot comment on your post, so I post it as an answer.
Your problem is that you have another entity TeachingEvent with a reference to TimeTableEntry. When you try to delete a TimeTableEntry, it is impossible because this time_table_entry_id is still referenced as a foreign key in the TeachingEvent table.
Before deleting the TimeTableEntry, first you should unlink it from the TeachingEvent. I don't have your code, but depending on how TimeTableEntry and TeachingEvent relate to each other, it's probably something like:
$teachingEvent->setTimeTableEntry(null);
or
$timeTableEntry->setTeachingEvent(null);
I updated my entity file to include relationship mapping.
Persist worked before the update now it doesn't.
Maybe it's something I forgot to do.
namespace classes\classBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* advisersplans
*
* #ORM\Table()
* #ORM\Entity
*/
class advisersPlans
{
/**
*
* #ORM\ManyToOne(targetEntity="plans", inversedBy="adviserPlans")
* #ORM\JoinColumn(name="planid", referencedColumnName="id")
*/
public $plan;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #var integer
*
* #ORM\Column(name="userid", type="integer")
*
*
*/
public $userid;
/**
* #var integer
*
* #ORM\Column(name="adviserid", type="integer")
*
*
*/
public $adviserid;
/**
* #var integer
*
* #ORM\Column(name="planid", type="integer")
*
*
*/
public $planid;
/**
* #var string
*
* #ORM\Column(name="participantLoginWebsiteAddress", type="string", length=255)
*/
public $participantLoginWebsiteAddress;
public function __construct()
{
$class_vars = get_class_vars(get_class($this));
foreach ($class_vars as $key => $value)
{
if ($key != "plan")
$this->$key = "";
}
}
}
Perist returns error saying planid is null. If I remove the following it works.
/**
*
* #ORM\ManyToOne(targetEntity="plans", inversedBy="adviserPlans")
* #ORM\JoinColumn(name="planid", referencedColumnName="id")
*/
Here is my code while persisting.
$adviserPlan = new advisersPlans();
$adviserPlan->planid = $planid;
$adviserPlan->userid = $this->userid();
$adviserPlan->adviserid = $session->get("editadviserid");
$em->persist($adviserPlan);
Am I supposed to populate the plan field and not the planid field or is my entity file coded wrong.
You shouldn't set ids. You should set entities:
$adviserPlan = new advisersPlans();
// You should retrieve the plan before doing this, of course.
$adviserPlan->setPlan($plan);
$plans->addAdviserPlan(§adviserPlan);
$em->persist($adviserPlan);
The methods for adding an entity to a collection should be generated by doctrine when you run:
php app/console doctrine:generate:entities YourBundle
I have a model which has many tables, but in this case we only need three.
The point is that the composite primary key of one is also the foreing key (composite too) and Symfony throws this exception:
MappingException: It is not possible to map entity 'Your\SomethingBundle\Entity\Empleado' with a composite primary key as part of the primary key of another entity 'Your\SomethingBundle\Entity\EmpleadoHorario#empleado'.
Here I explain the relationship:
1º Salon, it has a primary key ID
2º Empleado, it has a composite primary key ID, Salon_id and, also in the primary key, a foreing key referencing Salon: Salon_id
3º EmpleadoHorario: it has a composite primary key Fecha, Empleado_id, Salon_id and, also in the primary key, two a foreing keys referencing Salon: Salon_id, and Empleado: Empleado_id, Salon_id
All the relations has also the inverse union. Here is the code:
The Salon Entity:
/**
* Salon
*
* #ORM\Table(name="salon")
* #ORM\Entity
*/
class Salon
{
/**
* #var string
*
* #ORM\Column(name="id", type="string", length=50, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// More fields...
/**
* #var array_collection
*
* #ORM\OneToMany(targetEntity="Empleado", mappedBy="salon")
*/
private $empleados;
/**
* #var array_collection
*
* #ORM\OneToMany(targetEntity="EmpleadoHorario", mappedBy="salon")
*/
private $empleadoHorarios;
// Getters & Setters...
}
The Empleado Entity:
/**
* Empleado
*
* #ORM\Table(name="empleado")
* #ORM\Entity
*/
class Empleado
{
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $id;
/**
* #var string
*
* #ORM\JoinColumn(name="salon_id", referencedColumnName="id", nullable=false)
* #ORM\ManyToOne(targetEntity="Salon", inversedBy="empleados")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $salon;
// More fields...
/**
* #var array_collection
*
* #ORM\OneToMany(targetEntity="EmpleadoHorario", mappedBy="salon")
*/
private $empleadoHorarios;
// Getters & setters...
}
And finally the EmpleadoHorario Entity:
/**
* EmpleadoHorario
*
* #ORM\Table(name="empleado_horario")
* #ORM\Entity
*/
class EmpleadoHorario
{
/**
* #var \DateTime
*
* #ORM\Column(name="fecha", type="date", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $fecha;
/**
* #var string
*
* #ORM\JoinColumn(name="salon_id", referencedColumnName="id", nullable=false)
* #ORM\ManyToOne(targetEntity="Salon", inversedBy="empleadoHorarios")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $salon;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Empleado", inversedBy="empleadoHorarios")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="salon_id", referencedColumnName="salon_id", nullable=false),
* #ORM\JoinColumn(name="empleado_id", referencedColumnName="id", nullable=false)
* })
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $empleado;
// More fields...
// Getters & Setters...
}
As I said above, the problem seems to be in the EmpleadoHorario.empleado field, which is part of a composite primary key and also composite foreing key.
Other answers across StackOverflow.com suggest the Mapping Inheritance, but I don't even know how it works. I tried twice after reading this but I couldn't solve my problem.
This sample code is illustration of my (temporary) solution :
<?php
namespace X;
use Doctrine\ORM\Mapping as Orm;
/**
* #Orm\Entity
* #Orm\Table(name="A")
*/
class A {
/**
* #Orm\Id
* #Orm\Column(name="id", type="integer")
* #Orm\GeneratedValue(strategy="NONE")
*
* #var integer
*/
private $id;
/**
* #Orm\Id
*
* #var string
*/
private $otherId;
/**
* #Orm\OneToMany(targetEntity="B", fetch="LAZY", mappedBy="a")
*
* #var array
*/
private $collectionOfB;
// getter, setter and other props/methods
}
/**
* #Orm\Entity
* #Orm\Table(name="B")
*/
class B {
/**
* #Orm\Id
* #Orm\Column(name="code")
*
* #var string
*/
private $code;
/**
* #Orm\Id
* #Orm\Column(name="a_id", type="integer")
*
* #var integer
*/
private $a_id;
/**
* #Orm\Id
* #Orm\Column(name="a_other_id")
*
* #var integer
*/
private $a_other_id;
/**
* #Orm\ManyToOne(targetEntity="A", fetch="LAZY", inversedBy="collectionOfB")
* #Orm\JoinColumns({#Orm\JoinColumn(name="a_id", referencedColumnName="id"), #Orm\JoinColumn(name="a_other_id", referencedColumnName="other_id")})
*
* #var A
*/
private $a;
/**
* #Orm\OneToOne(targetEntity="C", fetch="LAZY", mappedBy="b")
*
* #var C
*/
private $c;
// bla bla bla
}
/**
* #Orm\Entity
* #Orm\Table(name="C")
*/
class C {
/**
* #Orm\Id
* #Orm\Column(name="a_id", type="integer")
*
* #var integer
*/
private $a_id;
/**
* #Orm\Id
* #Orm\Column(name="a_other_id")
*
* #var integer
*/
private $a_other_id;
/**
* #Orm\Id
* #Orm\Column(name="b_code")
*
* #var string
*/
private $b_code;
/**
*
* #Orm\OneToOne(targetEntity="B", fetch="LAZY", inversedBy="c")
* #Orm\JoinColumns({#Orm\JoinColumn(name="a_id", referencedColumnName="a_id"), #Orm\JoinColumn(name="a_other_id", referencedColumnName="a_other_id"), #Orm\JoinColumn(name="b_code", referencedColumnName="b_code")})
*
* #var B
*/
private $b;
// bla bla bla
}
Another also ugly solution is just to give AUTOINCREMENT unique PK for EmpleadoHorario like id for instance and remove #ORM\Id and #ORM\GeneratedValue(strategy="NONE") notations from EmpleadoHorario. So finally it will look like:
/**
* EmpleadoHorario
*
* #ORM\Table(name="empleado_horario")
* #ORM\Entity
*/
class EmpleadoHorario
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="fecha", type="date", nullable=false)
*/
private $fecha;
/**
* #var string
*
* #ORM\JoinColumn(name="salon_id", referencedColumnName="id", nullable=false)
* #ORM\ManyToOne(targetEntity="Salon", inversedBy="empleadoHorarios")
*/
private $salon;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Empleado", inversedBy="empleadoHorarios")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="salon_id", referencedColumnName="salon_id", nullable=false),
* #ORM\JoinColumn(name="empleado_id", referencedColumnName="id", nullable=false)
* })
*/
private $empleado;
// More fields...
// Getters & Setters...
}
I have three entities (Profile, ProfileValue and Value).
A Profile has a one-to-many relation with ProfileValue, which has a many-to-one relation with the Value entity.
Is it possible to get the rleated ProfileValues from the Profile, ordered by the value id?
If I add the orderby annotation for a non-foreign-key like the enabled field in ProfileValue, it works. But for a foreign key, it failed with the message "inrecognized field". Any ideas?
/**
*
* #ORM\Table(name="profile")
* #ORM\Entity
*/
class Profile {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var array $profileCValues
* #ORM\OneToMany(targetEntity="ABC\XYZBundle\Entity\ProfileValue", mappedBy="profile", cascade={"persist"})
* #ORM\OrderBy({"value" = "ASC"})
*/
private $profileValues;
And here is the ProfileValue entity:
/**
* ABC\XYZBundle\Entity\ProfileValue
*
* #ORM\Table(name="profile_value", indexes={#ORM\Index(columns={"profile_id"}), #ORM\Index(columns={"value_id"}) })
* #ORM\Entity
*/
class ProfileValue {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer $enabled
*
* #ORM\Column(name="enabled", type="boolean", length=1, nullable=true)
*/
private $enabled;
/**
* #var ABC\XYZBundle\Entity\Profile
* #ORM\ManyToOne(targetEntity="ABC\XYZBundle\Entity\Profile", inversedBy="profileValues")
* #ORM\JoinColumn(name="profile_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
private $profile;
/**
* #var ABC\XYZBundle\Entity\Value
* #ORM\ManyToOne(targetEntity="ABC\XYZBundle\Entity\Value")
* #ORM\JoinColumn(name="value_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $value;
}
Had the same problem and solved it by adding a new field with foreign key:
/**
* #var integer $valueId
*
* #ORM\Column(name="value_id", type="integer")
*/
private $valueId;
Then you can order it without problems:
/**
* #var array $profileCValues
* #ORM\OneToMany(targetEntity="ABC\XYZBundle\Entity\ProfileValue", mappedBy="profile", cascade={"persist"})
* #ORM\OrderBy({"valueId" = "ASC"})
*/
private $profileValues;
Does this work?
/**
* #var array $profileCValues
* #ORM\OneToMany(targetEntity="ABC\XYZBundle\Entity\ProfileValue", mappedBy="profile", cascade={"persist"})
* #ORM\OrderBy({"id" = "ASC"})
*/
private $profileValues;
I don't use XML but this works in YML:
oneToMany:
foos:
targetEntity: Company\ProjectBundle\Entity\Foo
mappedBy: bar
orderBy: { 'id': ASC }