Symfony Doctrine Insert: cannot insert into column "id" - php

I'm modeling a vending machine where I got 3 Entities (Milk, Sugar, Coffee) and one table that lists all my coffee machines.
Now I want to insert a new value for the amount of milk left. The coffee machines are foreign keys in the resources tables.
However, I get this error, which does not seem to make sense, as I am just setting a foreign key field:
An exception occurred while executing a query: SQLSTATE[428C9]: <<Unknown error>>: 7 ERROR: cannot insert into column "id"
DETAIL: Column "id" is an identity column defined as GENERATED ALWAYS.
HINT: Use OVERRIDING SYSTEM VALUE to override.
Here are the tables (Postgres) (only coffee listed - milk and sugar have the same architecture):
create table coffee (
id integer not null generated always as identity primary key,
request_id bigint,
logdate timestamp(0) without time zone not null,
vmc_no integer,
amount integer not null,
constraint fk_request
foreign key(request_id)
references energyomat.request(id),
constraint fk_vmc_company
foreign key(vmc_no)
references energyomat.vmc_company(vmc_no)
);
create table vmc_company (
vmc_no integer not null unique primary key,
register_date timestamp(0) without time zone not null
);
I've set the primitive fields and got the Entity of VmcCompany and set it as the foreign value (setVmcNo).
public function updateResources($vmcNo, $milkAmount, $sugarAmount, $coffeeAmount)
{
$milk = new Milk();
$sugar = new Sugar();
$coffee = new Coffee();
if($milkAmount != null) {
$milk->setAmount($milkAmount);
$milk->setLogdate(new \DateTime());
$vmc = $this->doctrine->getRepository(VmcCompany::class)->find($vmcNo);
$milk->setVmcNo($vmc);
$manager = $this->doctrine->getManager();
$manager->persist($milk);
}
if($sugarAmount != null) {
$sugar->setAmount($sugarAmount);
$sugar->setLogdate(new \DateTime());
$vmc = $this->doctrine->getRepository(VmcCompany::class)->find($vmcNo);
$sugar->setVmcNo($vmc);
$manager = $this->doctrine->getManager();
$manager->persist($sugar);
}
if($coffeeAmount != null) {
$coffee->setAmount($coffeeAmount);
$coffee->setLogdate(new \DateTime());
$vmc = $this->doctrine->getRepository(VmcCompany::class)->find($vmcNo);
$coffee->setVmcNo($vmc);
$manager = $this->doctrine->getManager();
$manager->persist($coffee);
}
$manager->flush();
}
Here are the Entity classes:
Coffee:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Coffee
*
* #ORM\Table(name="coffee", indexes={#ORM\Index(name="IDX_538529B3427EB8A5", columns={"request_id"}), #ORM\Index(name="IDX_538529B3651BF703", columns={"vmc_no"})})
* #ORM\Entity
*/
class Coffee
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="coffee_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="logdate", type="datetime", nullable=false)
*/
private $logdate;
/**
* #var int
*
* #ORM\Column(name="amount", type="integer", nullable=false)
*/
private $amount;
/**
* #var \Request
*
* #ORM\ManyToOne(targetEntity="Request")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="request_id", referencedColumnName="id")
* })
*/
private $request;
/**
* #var \VmcCompany
*
* #ORM\ManyToOne(targetEntity="VmcCompany")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="vmc_no", referencedColumnName="vmc_no")
* })
*/
private $vmcNo;
public function getId(): ?int
{
return $this->id;
}
public function getLogdate(): ?\DateTimeInterface
{
return $this->logdate;
}
public function setLogdate(\DateTimeInterface $logdate): self
{
$this->logdate = $logdate;
return $this;
}
public function getAmount(): ?int
{
return $this->amount;
}
public function setAmount(int $amount): self
{
$this->amount = $amount;
return $this;
}
public function getRequest(): ?Request
{
return $this->request;
}
public function setRequest(?Request $request): self
{
$this->request = $request;
return $this;
}
public function getVmcNo(): ?VmcCompany
{
return $this->vmcNo;
}
public function setVmcNo(?VmcCompany $vmcNo): self
{
$this->vmcNo = $vmcNo;
return $this;
}
}
VmcCompany:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* VmcCompany
*
* #ORM\Table(name="vmc_company")
* #ORM\Entity
*/
class VmcCompany
{
/**
* #var int
*
* #ORM\Column(name="vmc_no", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="vmc_company_vmc_no_seq", allocationSize=1, initialValue=1)
*/
private $vmcNo;
/**
* #var \DateTime
*
* #ORM\Column(name="register_date", type="datetime", nullable=false)
*/
private $registerDate;
public function getVmcNo(): ?int
{
return $this->vmcNo;
}
public function getRegisterDate(): ?\DateTimeInterface
{
return $this->registerDate;
}
public function setRegisterDate(\DateTimeInterface $registerDate): self
{
$this->registerDate = $registerDate;
return $this;
}
}
I'm new to Symfony / Doctrine and so I guess I'm overseeing something, but just cannot find out what it is. Thanks for your help in advance.

If someone else runs into this problem:
You need to declare the id field in the database table as follows:
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
The emphasis lies on BY DEFAULT instead of ALWAYS.
Otherwise Symfony runs into a conflict with Postgres while auto-incrementing.

Related

Doctrine2 entity , tell not update certain columns

I don't want to update certain columns for the table.
In the Questions table, I just want to update the question column:
question:
id
question
created_by
created_at
modified_by
modified_at
is_Active
In the above table column, I don't need to update the create_at, created_by, modified_by, modified_at, is_active columns. This is the entity I am using.
Entity:
<?php
namespace Library\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Base class for all the Entities
* This class maps id, active, created and modified columns
*
* #author
*/
/**
* #ORM\MappedSuperclass
*/
class BaseEntity {
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="id", type="integer")
* #var integer
*/
protected $id;
/**
* #ORM\Column(name="is_active", type="boolean")
* #var boolean
*/
protected $active;
/**
* #ORM\Column(name="created_at", type="datetime")
* #var datetime
*/
protected $createdAt;
/**
* #ORM\Column(name="created_by", type="integer", nullable=true)
* #var integer
*/
protected $createdBy;
/**
* #ORM\Column(name="modified_at", type="datetime")
* #var datetime
*/
protected $modifiedAt;
/**
* #ORM\Column(name="modified_by", type="integer")
* #var integer
*/
protected $modifiedBy;
public function getId() {
return $this->id;
}
public function getActive() {
return $this->active;
}
public function getCreatedAt() {
return $this->createdAt;
}
public function getCreatedBy() {
return $this->createdBy;
}
public function getModifiedAt() {
return $this->modifiedAt;
}
public function getModifiedBy() {
return $this->modifiedBy;
}
public function setId($id) {
$this->id = $id;
}
public function setActive($active) {
$this->active = $active;
}
public function setCreatedAt($createdAt) {
$this->createdAt = $createdAt;
}
public function setCreatedBy($createdBy) {
$this->createdBy = $createdBy;
}
public function setModifiedAt($modifiedAt) {
$this->modifiedAt = $modifiedAt;
}
public function setModifiedBy($modifiedBy) {
$this->modifiedBy = $modifiedBy;
}
}
This is my Question Entity:
<?php
namespace Survey\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Library\Entity\BaseEntity;
use Survey\Entity\Survey;
/**
* Description of Survey Questions
*
* #author Mubarak
*/
/**
* #ORM\Entity
* #ORM\Table(name="survey_questions")
*/
class Question extends BaseEntity{
/**
* #ORM\Column(name="question", type="string")
* #var string
*/
protected $question;
/**
* #ORM\ManyToOne(targetEntity="Survey\Entity\Survey", inversedBy="questions")
* #ORM\JoinColumn(name="survey_id", referencedColumnName="id")
*/
private $surveys;
public function getQuestion() {
return $this->question;
}
public function setQuestion($question) {
$this->question = $question;
}
public function getSurveys() {
return $this->surveys;
}
// public function setSurveys(ArrayCollection $survey) {
public function setSurveys(Survey $surveys = null) {
$this->surveys = $surveys;
}
// public function __toString() {
// return __CLASS__ . ": [id: {$this->id}, name: {$this->name}]";
// }
}
Here is my update function:
public function updateQuestion($userId, $data ) {
try{
$surveyId = 1;
$survey = $this->entityManager->getRepository('Survey\Entity\Survey')->find($surveyId);
$question = new Question();
$question->setQuestion($data['question']);
$question->setSurveys($survey);
$question->setId(1);
$this->entityManager->merge($question);
$this->entityManager->flush();
} catch (Exception $ex) {
throw new Exception("Couldnt update the Question");
}
Below is my error message i am getting:
An exception occurred while executing 'UPDATE survey_questions SET is_active = ?, created_at = ?, created_by = ?, modified_at = ?, modified_by = ? WHERE id = ?' with params [null, null, null, null, null, 1]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1048 Column 'created_at' cannot be null
Here is my insert Operation:
public function insertQuestion($userId, $survey, $questionArr) {
try{
$question = new Question();
$question->setQuestion($questionArr['question']);
$question->setSurveys($survey);
$question->setActive(1);
$question->setCreatedBy($userId);
$question->setCreatedAt($this->createdAt);
$question->setModifiedBy($userId);
$question->setModifiedAt($this->modifiedAt);
$this->entityManager->persist($question);
$this->entityManager->flush();
return $question;
}catch(Exception $ex){
throw new Exception("Couldnt insert the question");
}
}
The problem is that you are creating a new entity, Question.
When calling EntityManager::flush() Doctrine computes the changesets of all the currently managed entities and saves the differences to the database. In case of object properties (#Column(type=”datetime”) or #Column(type=”object”)) these comparisons are always made BY REFERENCE.
"By reference" is important because your new entity has null values for all date time fields (rather than the previously set \DateTime instances). When flush() is called Doctrine correctly detects that these fields are changed and performs the query which fails at the database level.
The merge() operation isn't required in Doctrine when 'editing' entities, these are used for detached instances that need to be managed again.
To solve this you should load the managed instance of the entity first; then modify the fields and flush.
$question = $entityManager->find(1);
$question->setQuestion($data['question']);
$entityManager->flush();

Doctrine 2: How to update one-to-one bidirectional

I have problem with updating one-to-one bidirectional association.
User Entity
/**
*
* #ORM\Table(name="test_user")
*/
class User
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="login", type="string", length=32, nullable=false, unique=true)
*/
private $login;
/**
*
* #ORM\OneToOne(targetEntity="Points", mappedBy="user", cascade={"persist"})
*/
private $points;
...
/**
* Set points
*/
public function setPoints(array $points)
{
$this->points = new Points($points);
$this->points->setUser($this);
return $this;
}
/**
* Get points
*/
public function getPoints()
{
return $this->points;
}
}
Points Entity
/**
* Points
*
* #ORM\Table(name="test_user_points")
* #ORM\Entity
*/
class Points {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(type="integer", nullable=false)
*/
private $points;
/**
* #var string
*
* #ORM\Column(name="period", type="string", length=24)
*/
private $period;
/**
* #var User
*
* #ORM\OneToOne(targetEntity="User", inversedBy="points")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id",onDelete="CASCADE", nullable=false)
*/
private $user;
/**
* Constructor
*/
public function __construct(array $params = array())
{
$hydrator = new MyHydrator();
$hydrator->hydrate($params, $this);
}
...
/**
* Set user
*
* #param User $user
*/
public function setUser(User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return User
*/
public function getUser()
{
return $this->user;
}
}
Class MyHydrator is converting from array(first param) to object(second param). It is very important and I have to use it.
My save function looks like this:
public function save(array $data)
{
...
// This is how my input data looks
$data = array(
'login' => 'Test',
array(
'points' => 999,
'period' => 'monthly'
)
);
if ($userExists) {
// UPDATE
$hydrator = new MyHydrator();
$hydrator->hydrate($data, $userExists);
$this->em->persist($userExists);
$this->em->flush();
} else {
// INSERT
$user = new User($data);
$this->em->persist($user);
$this->em->flush();
}
}
Inserting to database works perfect, but when I try to update record I get error:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '4' for key 'UNIQ_DAD93D6EA76ED395'
4 is a value of user_id column in points table
How can I edit existing record without error about duplicate id?
It's old but since I encoutered a similar issue, I resolved it this way :
in User
public function setPoints($points)
{
if ($this->points !== null) {
$this->points->setUser(null);
}
$this->points = $points;
$points->setUser($this);
}

Overlapped Non Primary Key for Composite Foreign Key Doctrine Symfony 2

I'm trying to construct four entities using Doctrine Symfony 2.
One of the entities has "Overlapped or Intersected Non Primary Key Composite Foreign Key" - apologize for my bad English.
I've tried to modify doctrine object but I can't still persist all the entities to PostgreSQL.
Below the doctrine objects of four entities I've constructed:
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyContinentRepository")
* #ORM\Table(
* name="geography_continent",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_continent_u1", columns={"continent_name"})
* }
* )
*/
class GeographyContinent
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="continent_name", type="string", nullable=false)
*/
protected $continentName;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set continentName
*
* #param string $continentName
* #return GeographyContinent
*/
public function setContinentName($continentName)
{
$this->continentName = $continentName;
return $this;
}
/**
* Get continentName
*
* #return string
*/
public function getContinentName()
{
return $this->continentName;
}
/**
* Set description
*
* #param string $description
* #return GeographyContinent
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
?>
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyCountryRepository")
* #ORM\Table(
* name="geography_country",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_country_u1", columns={"country_name"}),
* #ORM\UniqueConstraint(name="geography_country_u2", columns={"telephone_code"}),
* #ORM\UniqueConstraint(name="geography_country_u3", columns={"currency_name"}),
* #ORM\UniqueConstraint(name="geography_country_u4", columns={"currency_symbol"})
* }
* )
*/
class GeographyCountry
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="country_name", type="string", nullable=false)
*/
protected $countryName;
/**
*
* #ORM\Column(name="telephone_code", type="string", nullable=true)
*/
protected $telephoneCode;
/**
*
* #ORM\Column(name="currency_name", type="string", nullable=true)
*/
protected $currencyName;
/**
*
* #ORM\Column(name="currency_symbol", type="string", nullable=true)
*/
protected $currencySymbol;
/**
*
* #ORM\Column(name="continent_id", type="integer", nullable=false)
*/
protected $continentId;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyContinent", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="continent_id", referencedColumnName="id")
*/
protected $fkContinent;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set countryName
*
* #param string $countryName
* #return GeographyCountry
*/
public function setCountryName($countryName)
{
$this->countryName = $countryName;
return $this;
}
/**
* Get countryName
*
* #return string
*/
public function getCountryName()
{
return $this->countryName;
}
/**
* Set telephoneCode
*
* #param string $telephoneCode
* #return GeographyCountry
*/
public function setTelephoneCode($telephoneCode)
{
$this->telephoneCode = $telephoneCode;
return $this;
}
/**
* Get telephoneCode
*
* #return string
*/
public function getTelephoneCode()
{
return $this->telephoneCode;
}
/**
* Set currencyName
*
* #param string $currencyName
* #return GeographyCountry
*/
public function setCurrencyName($currencyName)
{
$this->currencyName = $currencyName;
return $this;
}
/**
* Get currencyName
*
* #return string
*/
public function getCurrencyName()
{
return $this->currencyName;
}
/**
* Set currencySymbol
*
* #param string $currencySymbol
* #return GeographyCountry
*/
public function setCurrencySymbol($currencySymbol)
{
$this->currencySymbol = $currencySymbol;
return $this;
}
/**
* Get currencySymbol
*
* #return string
*/
public function getCurrencySymbol()
{
return $this->currencySymbol;
}
/**
* Set continentId
*
* #param integer $continentId
* #return GeographyCountry
*/
public function setContinentId($continentId)
{
$this->continentId = $continentId;
return $this;
}
/**
* Get continentId
*
* #return integer
*/
public function getContinentId()
{
return $this->continentId;
}
/**
* Set description
*
* #param string $description
* #return GeographyCountry
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set fkContinent
*
* #param \EntityBundle\Entity\GeographyContinent $fkContinent
* #return GeographyCountry
*/
public function setFkContinent(\EntityBundle\Entity\GeographyContinent $fkContinent = null)
{
$this->fkContinent = $fkContinent;
return $this;
}
/**
* Get fkContinent
*
* #return \EntityBundle\Entity\GeographyContinent
*/
public function getFkContinent()
{
return $this->fkContinent;
}
}
?>
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyProvinceRepository")
* #ORM\Table(
* name="geography_province",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_province_u1", columns={"country_id", "id"}),
* #ORM\UniqueConstraint(name="geography_province_u2", columns={"country_id", "province_name"})
* }
* )
*/
class GeographyProvince
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="province_name", type="string", nullable=false)
*/
protected $provinceName;
/**
* #ORM\Column(name="country_id", type="integer", nullable=false)
*/
protected $countryId;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyCountry", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $fkCountry;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set provinceName
*
* #param string $provinceName
* #return GeographyProvince
*/
public function setProvinceName($provinceName)
{
$this->provinceName = $provinceName;
return $this;
}
/**
* Get provinceName
*
* #return string
*/
public function getProvinceName()
{
return $this->provinceName;
}
/**
* Set countryId
*
* #param integer $countryId
* #return GeographyProvince
*/
public function setCountryId($countryId)
{
$this->countryId = $countryId;
return $this;
}
/**
* Get countryId
*
* #return integer
*/
public function getCountryId()
{
return $this->countryId;
}
/**
* Set description
*
* #param string $description
* #return GeographyProvince
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set fkCountry
*
* #param \EntityBundle\Entity\GeographyCountry $fkCountry
* #return GeographyProvince
*/
public function setFkCountry(\EntityBundle\Entity\GeographyCountry $fkCountry = null)
{
$this->fkCountry = $fkCountry;
return $this;
}
/**
* Get fkCountry
*
* #return \EntityBundle\Entity\GeographyCountry
*/
public function getFkCountry()
{
return $this->fkCountry;
}
}
?>
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyCityRepository")
* #ORM\Table(
* name="geography_city",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_city_u1", columns={"province_id", "is_municipality", "city_name"})
* }
* )
*/
class GeographyCity
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="city_name", type="string", nullable=false)
*/
protected $cityName;
/**
*
* #ORM\Column(name="is_municipality", type="boolean", nullable=true)
*/
protected $isMunicipality;
/**
*
* #ORM\Column(name="province_id", type="integer", nullable=true)
*/
protected $provinceId;
/**
*
* #ORM\Column(name="country_id", type="integer", nullable=false)
*/
protected $countryId;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyCountry", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="country_id", referencedColumnName="id", nullable=false)
*/
protected $fkCountry;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyProvince", cascade={"persist", "remove"})
* #ORM\JoinColumns
* (
* {
* #ORM\JoinColumn(name="country_id", referencedColumnName="country_id", nullable=false),
* #ORM\JoinColumn(name="province_id", referencedColumnName="id", nullable=true)
* }
* )
*/
protected $fkProvince;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set cityName
*
* #param string $cityName
* #return GeographyCity
*/
public function setCityName($cityName)
{
$this->cityName = $cityName;
return $this;
}
/**
* Get cityName
*
* #return string
*/
public function getCityName()
{
return $this->cityName;
}
/**
* Set isMunicipality
*
* #param boolean $isMunicipality
* #return GeographyCity
*/
public function setIsMunicipality($isMunicipality)
{
$this->isMunicipality = $isMunicipality;
return $this;
}
/**
* Get isMunicipality
*
* #return boolean
*/
public function getIsMunicipality()
{
return $this->isMunicipality;
}
/**
* Set provinceId
*
* #param integer $provinceId
* #return GeographyCity
*/
public function setProvinceId($provinceId)
{
$this->provinceId = $provinceId;
return $this;
}
/**
* Get provinceId
*
* #return integer
*/
public function getProvinceId()
{
return $this->provinceId;
}
/**
* Set countryId
*
* #param integer $countryId
* #return GeographyCity
*/
public function setCountryId($countryId)
{
$this->countryId = $countryId;
return $this;
}
/**
* Get countryId
*
* #return integer
*/
public function getCountryId()
{
return $this->countryId;
}
/**
* Set description
*
* #param string $description
* #return GeographyCity
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set fkCountry
*
* #param \EntityBundle\Entity\GeographyCountry $fkCountry
* #return GeographyCity
*/
public function setFkCountry(\EntityBundle\Entity\GeographyCountry $fkCountry)
{
$this->fkCountry = $fkCountry;
return $this;
}
/**
* Get fkCountry
*
* #return \EntityBundle\Entity\GeographyCountry
*/
public function getFkCountry()
{
return $this->fkCountry;
}
/**
* Set fkProvince
*
* #param \EntityBundle\Entity\GeographyProvince $fkProvince
* #return GeographyCity
*/
public function setFkProvince(\EntityBundle\Entity\GeographyProvince $fkProvince)
{
$this->fkProvince = $fkProvince;
return $this;
}
/**
* Get fkProvince
*
* #return \EntityBundle\Entity\GeographyProvince
*/
public function getFkProvince()
{
return $this->fkProvince;
}
}
?>
The four entities above able to generate SQL DDL PostgreSQL properly.
Below the generated sql (with few modifications):
CREATE TABLE geography_continent
(
id INT NOT NULL,
continent_name VARCHAR(255) NOT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE TABLE geography_country
(
id INT NOT NULL,
continent_id INT NOT NULL,
country_name VARCHAR(255) NOT NULL,
telephone_code VARCHAR(255) DEFAULT NULL,
currency_name VARCHAR(255) DEFAULT NULL,
currency_symbol VARCHAR(255) DEFAULT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE TABLE geography_province
(
id INT NOT NULL,
country_id INT NOT NULL,
province_name VARCHAR(255) NOT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE TABLE geography_city
(
id INT NOT NULL,
country_id INT NOT NULL,
province_id INT DEFAULT NULL,
city_name VARCHAR(255) NOT NULL,
is_municipality BOOLEAN DEFAULT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE SEQUENCE geography_continent_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE geography_country_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE geography_province_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE geography_city_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE UNIQUE INDEX geography_continent_u1 ON geography_continent (continent_name);
CREATE INDEX IDX_6D7254DD921F4C77 ON geography_country (continent_id);
CREATE UNIQUE INDEX geography_country_u1 ON geography_country (country_name);
CREATE UNIQUE INDEX geography_country_u2 ON geography_country (telephone_code);
CREATE UNIQUE INDEX geography_country_u3 ON geography_country (currency_name);
CREATE UNIQUE INDEX geography_country_u4 ON geography_country (currency_symbol);
CREATE INDEX IDX_1657BF92F92F3E70 ON geography_province (country_id);
CREATE UNIQUE INDEX geography_province_u1 ON geography_province (country_id, id);
CREATE UNIQUE INDEX geography_province_u2 ON geography_province (country_id, province_name);
CREATE INDEX IDX_3F82CFCAF92F3E70 ON geography_city (country_id);
CREATE INDEX IDX_3F82CFCAF92F3E70E946114A ON geography_city (country_id, province_id);
CREATE UNIQUE INDEX geography_city_u1 ON geography_city (province_id, is_municipality, city_name);
ALTER TABLE geography_country ADD CONSTRAINT FK_6D7254DD921F4C77 FOREIGN KEY (continent_id) REFERENCES geography_continent (id) MATCH FULL ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE geography_province ADD CONSTRAINT FK_1657BF92F92F3E70 FOREIGN KEY (country_id) REFERENCES geography_country (id) MATCH FULL ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE geography_city ADD CONSTRAINT FK_3F82CFCAF92F3E70 FOREIGN KEY (country_id) REFERENCES geography_country (id) MATCH FULL ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
-- MATCH SIMPLE FOREIGN KEY
ALTER TABLE geography_city ADD CONSTRAINT FK_3F82CFCAF92F3E70E946114A FOREIGN KEY (country_id, province_id) REFERENCES geography_province (country_id, id) MATCH SIMPLE ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
Table "geography_city" have two foreign keys.
One refers to table "geography_country" with column "country_id".
The other refers to table "geography_province" with two columns "country_id" and "province_id", column "province_id" is optional and may NULL (signed as "MATCH SIMPLE" FOREIGN KEY) because perhaps A City of A Country does not have province.
Below main php code of the controller to persist the four entities above:
<?php
$geographyContinentName = "A Continent Name";
$geographyContinent = new GeographyContinent();
$geographyContinent->setContinentName($geographyContinentName);
$geographyCountryName = "A Country Name";
$geographyCountry = new GeographyCountry();
$geographyCountry->setCountryName($geographyCountryName);
$geographyCountry->setFkContinent($geographyContinent);
$geographyProvinceName = "A Province Name";
$geographyProvince = new GeographyProvince();
$geographyProvince->setProvinceName($geographyProvinceName);
$geographyProvince->setFkCountry($geographyCountry);
$geographyCityName = "A City Name";
$geographyCity = new GeographyCity();
$geographyCity->setCityName($geographyCityName);
$geographyCity->setFkCountry($geographyCountry);
$geographyCity->setFkProvince($geographyProvince);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($geographyContinent);
$entityManager->persist($geographyCountry);
$entityManager->persist($geographyProvince);
$entityManager->persist($geographyCity);
$entityManager->flush();
?>
Below the errors produced after running the controller above:
[2013-12-15 06:41:38] request.INFO:
Matched route "entity_geography_create"
(
parameters:
"_controller": "Entity\GeographyBundle\Controller\CreateController::indexAction",
"_route": "entity_geography_create"
)
[2013-12-15 06:41:38] app.ERROR:
Doctrine\DBAL\DBALException:
An exception occurred while executing
'INSERT INTO geography_city (id, city_name, is_municipality, province_id, country_id, description) VALUES (?, ?, ?, ?, ?, ?)'
with params [1, "A City Name", null, 1, null, null]
SQLSTATE[23502]: Not null violation
ERROR: null value in column "country_id" violates not-null constraint
(uncaught exception) at D:\server\htdocs\application\vendor\doctrine\dbal\lib\Doctrine\DBAL\DBALException.php line 47
I expect that value of column "country_id" will be provided automatically when inserting into table "geography_city", but based on the errors above it does not.
Any help I would really appreciate.
Thank you very much.
Best Regards.
#n.1 Many thanks for your kind help.
My full transaction code running well.
I execute commands:
php app/console doctrine:cache:clear-metadata
php app/console doctrine:cache:clear-query
php app/console doctrine:cache:clear-result
php app/console cache:clear --no-warmup
My problem is solved now.
Thanks God.
I just encountered the same problem and solved it by calling $entityManager->flush(); after every call to $entityManager->persist($your_new_entity);. It will ensure that the persisted entity will have an id, so this id will be available for the other entity which use it as a foreign key.
So you have to call
$entityManager->persist($your_new_entity);
$entityManager->flush();
before using the new entity as a foreign key.
It seems to be feasible by defining cascade operations, see the documentation of Doctrine2 about Persisting entities for more information.

Symfony2's Doctrine does not create one-to-many structure for me

I have two tables. First table is users and second is datas. Datas has useridx column which is foreign with user's idx. (primary unique key).
These are the table structures:
Table users
CREATE TABLE public.users (
idx bigint NOT NULL,
"name" varchar(250) DEFAULT NULL::character varying,
surname varchar(250) DEFAULT NULL::character varying,
isactive boolean NOT NULL DEFAULT false,
/* Keys */
CONSTRAINT users_pkey
PRIMARY KEY (idx),
CONSTRAINT users_idx_key
UNIQUE (idx)
) WITH (
OIDS = FALSE
);
Table datas:
CREATE TABLE public.datas (
idx bigint NOT NULL,
useridx bigint,
phrase varchar(100) DEFAULT NULL::character varying,
response varchar(100) DEFAULT NULL::character varying,
/* Keys */
CONSTRAINT datas_pkey
PRIMARY KEY (idx),
CONSTRAINT datas_idx_key
UNIQUE (idx),
/* Foreign keys */
CONSTRAINT fk_cf180c1a262768b5
FOREIGN KEY (useridx)
REFERENCES public.users(idx)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) WITH (
OIDS = FALSE
);
Now when i run these commands:
app/console doctrine:mapping:convert yml
./src/Acme/DemoBundle/Resources/config/doctrine/metadata/orm
--from-database
--force
And;
app/console doctrine:mapping:import AcmeDemoBundle annotation
app/console doctrine:generate:entities AcmeDemoBundle
I got this result:
Datas.php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\DemoBundle\Entity\Datas
*
* #ORM\Table(name="datas")
* #ORM\Entity
*/
class Datas
{
/**
* #var bigint $idx
*
* #ORM\Column(name="idx", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="datas_idx_seq", allocationSize="1", initialValue="1")
*/
private $idx;
/**
* #var string $phrase
*
* #ORM\Column(name="phrase", type="string", length=100, nullable=true)
*/
private $phrase;
/**
* #var string $response
*
* #ORM\Column(name="response", type="string", length=100, nullable=true)
*/
private $response;
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="useridx", referencedColumnName="idx")
* })
*/
private $useridx;
/**
* Get idx
*
* #return bigint
*/
public function getIdx()
{
return $this->idx;
}
/**
* Set phrase
*
* #param string $phrase
*/
public function setPhrase($phrase)
{
$this->phrase = $phrase;
}
/**
* Get phrase
*
* #return string
*/
public function getPhrase()
{
return $this->phrase;
}
/**
* Set response
*
* #param string $response
*/
public function setResponse($response)
{
$this->response = $response;
}
/**
* Get response
*
* #return string
*/
public function getResponse()
{
return $this->response;
}
/**
* Set useridx
*
* #param Acme\DemoBundle\Entity\Users $useridx
*/
public function setUseridx(\Acme\DemoBundle\Entity\Users $useridx)
{
$this->useridx = $useridx;
}
/**
* Get useridx
*
* #return Acme\DemoBundle\Entity\Users
*/
public function getUseridx()
{
return $this->useridx;
}
}
?>
Users.php
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\DemoBundle\Entity\Users
*
* #ORM\Table(name="users")
* #ORM\Entity
*/
class Users
{
/**
* #var bigint $idx
*
* #ORM\Column(name="idx", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="users_idx_seq", allocationSize="1", initialValue="1")
*/
private $idx;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=250, nullable=true)
*/
private $name;
/**
* #var string $surname
*
* #ORM\Column(name="surname", type="string", length=250, nullable=true)
*/
private $surname;
/**
* #var boolean $isactive
*
* #ORM\Column(name="isactive", type="boolean", nullable=false)
*/
private $isactive;
/**
* Get idx
*
* #return bigint
*/
public function getIdx()
{
return $this->idx;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set surname
*
* #param string $surname
*/
public function setSurname($surname)
{
$this->surname = $surname;
}
/**
* Get surname
*
* #return string
*/
public function getSurname()
{
return $this->surname;
}
/**
* Set isactive
*
* #param boolean $isactive
*/
public function setIsactive($isactive)
{
$this->isactive = $isactive;
}
/**
* Get isactive
*
* #return boolean
*/
public function getIsactive()
{
return $this->isactive;
}
}
?>
I also have yml files but i dont think they are necessary in here only PHP files i posted here.
Now, when i run this command inside of my controller:
<?php
$user = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Users')
->find(24);
$phrase = $user->getDatas()->getPhrase();
?>
I got an error that say Call to a member function getDatas() on a non-object.... I know it is clear. In Users.php i don't have getDatas().
But what i read from Symfony2 and Doctrine documentation is it should be there because they are related. All i want to do is get Datas inside of Users.
What is my mistake here? What im missing?
Update:
I added this lines to the Users.php
<?php
/**
* #var \Acme\DemoBundle\Entity\Datas
*
* #ORM\OneToMany(targetEntity="Datas", mappedBy="datas", cascade={"all"})
*/
private $datas;
public function __construct()
{
$this->datas = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add phrases
*
* #param Acme\DemoBundle\Entity\Datas $datas
*/
public function addPhrases(\Acme\DemoBundle\Entity\Datas $datas)
{
$this->datas[] = $datas;
}
/**
* Get datas
*
* #return Doctrine\Common\Collections\Collection
*/
public function getDatas()
{
return $this->datas;
}
?>
And these lines to the Datas.php
<?php
/**
* #ORM\ManyToOne(targetEntity="Users", inversedBy="users", cascade={"all"})
*/
protected $users;
/**
* Set users
*
* #param Acme\DemoBundle\Entity\Users $users
*/
public function setUsers(\Acme\DemoBundle\Entity\Users $users)
{
$this->users = $users;
}
/**
* Get users
*
* #return Acme\DemoBundle\Entity\Users
*/
public function getUsers()
{
return $this->users;
}
?>
Now getDatas() is working but inside of it is not. ($user->getDatas()->getPhrase();)
I am getting this error:
Call to undefined method Doctrine\ORM\PersistentCollection::getPhrase()
Conclusion: I got collection error because it returns a collection -of course-. Iterate (like foreach) it and you will access the data. (If you encounter a problem like this.)
If look at the documentation of #JoinColumn
This annotation is used in the context of relations in #ManyToOne, #OneToOne fields and in the Context of #JoinTable nested inside a #ManyToMany. This annotation is not required. If its not specified the attributes name and referencedColumnName are inferred from the table and primary key names.
So as you are using ManyToOne relation your relation definition would be,
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users")
* #ORM\JoinColumn(name="useridx", referencedColumnName="idx")
*/
private $useridx;
Edit:
If you want to get datas from user side then you have to create OneToMany relation. e.g
In Datas.php
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users", inversedBy = "datas")
* #ORM\JoinColumn(name="useridx", referencedColumnName="idx")
*/
private $useridx;
And in Users.php add following line,
/**
* #ORM\OneToMany(targetEntity="Datas", mappedBy="useridx", cascade={"persist"})
*/
protected $datas;
And then do a doctrine:generate:entities command. To do operations on relation check this doc entry.

Primary key and foreign key at the same time with doctrine 2

I have the two tables :
table A with id as primary key
table B with id as primary key and foreign key
Explanation on short:
I need to have in table B a primary key that also to be a foreign key that points to table A's primary key.
Can anybody explain me how to map this by annotations in Doctrine 2?
Note:
I tried it By this :
class A
{
/**
* #var bigint $id
*
* #Column(name="id", type="bigint", nullable=false)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $a_id;
...
and B table:
class B
{
/**
* #var bigint $id
* #Id
* #OneToOne(targetEntity="A", fetch="LAZY")
* #JoinColumn(name="id", referencedColumnName="id")
*/
private $b_id;
...
But it gives me this error:
Uncaught exception
'Doctrine\ORM\Mapping\MappingException'
with message 'No identifier/primary
key specified for Entity 'B'. Every
Entity must have an identifier/primary
key.' in
/var/www/agr-reg-php/Doctrine/ORM/Mapping/MappingException.php:37
Stack trace:
N.B: I must not have composite primary key.
This is possible since Doctrine 2.1:
Identity through Foreign Entities or derived entities: You can now use a foreign key as identifier of an entity. This translates to using #Id on a #ManyToOne or #OneToOne association. You can read up on this feature in the tutorial.
I could solve the problem, creating a pk field with the same name to the foreign field
class B
{
/**
* #var bigint $a_id
* #Id #Column(name="a_id", type="bigint", nullable="false")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $a_id;
/**
* #OneToOne(targetEntity="A", fetch="LAZY")
* #JoinColumn(name="id", referencedColumnName="id")
*/
private $a;
.
.
.
/**
* #var A
*
* #ORM\OneToOne(targetEntity="A")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="a_id", referencedColumnName="id", unique=true)
* })
*/
private $a;
//...
I had the same task and experimentaly found this solution:
class A {
/**
* #Id #Column(type="integer", nullable=false)
* #GeneratedValue
*/
protected $id;
/**
* #OneToOne(targetEntity="B", inversedBy="a", orphanRemoval=true, cascade={"persist", "remove"})
* #JoinColumn(name="id", referencedColumnName="id")
*/
protected $b;
}
class B {
/**
* #OneToOne(targetEntity="A", mappedBy="b" )
*/
protected $user;
/**
* #Id
* #Column(type="integer", nullable=false)
* #GeneratedValue
*/
protected $id;
}
Finally I resolved my problem by specifying two fields in my entity class for the same column from real table. The changes are made only in class B (look at the question for class A):
class B
{
/**
* #var bigint $id
* #Id #Column(name="id", type="bigint", nullable="false")
*/
private $b_id;
/**
* #OneToOne(targetEntity="A", fetch="LAZY")
* #JoinColumn(name="id", referencedColumnName="id")
*/
private $a;
...
In fact all what I have done is write two fields in my entity for the same primary key and foreign key.
Well this is other temporal solution for insert:
/**
* #Entity
* #Table(name="types")
*/
class Type {
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
private $id;
/**
* #OneToMany(targetEntity="type\models\Language", mappedBy="type")
*/
private $languages;
/**
* #Column(type="string", length = 45,nullable = true)
*/
private $category;
/**
* #Column(type="string", length = 1)
*/
private $status;
/**
* #Column(type="string", length = 45)
*/
private $name;
/**
* #Column(type="datetime", nullable = true)
*/
private $datedeleted;
/**
* #Column(type="datetime", nullable = true)
*/
private $datemodificated;
/**
* #Column(type="datetime")
*/
private $dateregistered;
public function __construct() {
$this->languages = new \Doctrine\Common\Collections\ArrayCollection;
$this->status = 1;
$this->dateregistered = new \DateTime("now");
}
public function id() {
return $this->id;
}
public function category($value = NULL) {
if (is_null($value))
return $this->category;
else
$this->category = $value;
}
public function name($value = NULL) {
if (is_null($value))
return $this->name;
else
$this->name = $value;
}
public function status($value = NULL) {
if (is_null($value))
return $this->status;
else
$this->status = $value;
}
public function datedeleted($value = NULL) {
if (is_null($value))
return $this->datedeleted;
else
$this->datedeleted = $value;
}
public function datemodificated($value = NULL) {
if (is_null($value))
return $this->datemodificated;
else
$this->datemodificated = $value;
}
public function dateregistered($value = NULL) {
if (is_null($value))
return $this->dateregistered;
else
$this->dateregistered = $value;
}
}
/**
* #Entity
* #Table(name="languages")
*/
class Language {
/**
* #Id
* #Column(name="type_id", type="integer", nullable="false")
*/
private $language_id;
/**
* #Id
* #ManyToOne(targetEntity="type\models\Type",inversedBy="languages")
* #JoinColumn(name="type_id", referencedColumnName="id")
*/
private $type;
/**
* #Column(type="string", length = 100, nullable = true)
*/
private $description;
/**
* #Id
* #Column(type="string", length = 20)
*/
private $language;
public function language_id($value) {
$this->language_id = $value;
}
public function description($value = NULL) {
if (is_null($value))
return $this->description;
else
$this->description = $value;
}
public function language($value = NULL) {
if (is_null($value))
return $this->language;
else
$this->language = $value;
}
public function type($value = NULL) {
if (is_null($value))
return $this->type;
else
$this->type = $value;
}
}
$language = new Language;
$xtype_id = $this->em->find("Type",1);
$language->language_id($xtype_id->id());
$language->type($xtype_id);
$language->description($xdescription);
$language->language($xlanguage);
$this->em->persist($this);
$this->em->flush();
this insert in a Class With the foreign key and primary key in language

Categories