Reputation: 1523
I am new to Symfony and trying to setup entities and relationships. Even though I seemed to have correctly annotated the primary keys.
When running
php bin/console doctrine:schema:validate
I got an error as follows:
The referenced column name 'brandId' has to be a primary key column on the target entity class 'AppBundle\Entity\Brands'.
The entities look like ( only relevant portions):
Thanks
Brands
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity
* @ORM\Table(name="brands")
*/
class Brands
{
/**
* @ORM\Id
* @ORM\Column(type="smallint",length=3,unique=true,options={"unsigned":true})
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $brandId;
/**
* one brands has many models
* @ORM\OneToMany(targetEntity="Models", mappedBy="brandId")
* @ORM\JoinColumn(name="brandId", referencedColumnName="brandId")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
Models:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\ModelsRepository")
* @ORM\Table(name="models")
*/
class Models
{
/**
* @ORM\Column(type="smallint",length=4,unique=true,options={"unsigned":true})
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $modelId;
/**
* @ORM\Column(type="string", length=25)
*/
private $model;
/**
* Many models for one brand
* @ORM\ManyToOne(targetEntity="Brands",inversedBy="models")
* @ORM\JoinColumn(name="brandId", referencedColumnName="brandId")
*/
private $brandId;
Upvotes: 1
Views: 1273
Reputation: 1523
This all ended up being an issue with Doctrine's naming strategy, which I did not know about. See this article for details
That strategy was set as default, while I was trying to adapt mysql's underscore naming strategy to PHP's camel case naming strategy. This was causing Symfony not to find the primary and thus the error.
Once I learned about that and with the valuable input I've received with this post, I have refactored the entities as below:
Thank you all.
Brands
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity
* @ORM\Table(name="brands")
*/
class Brands
{
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(type="smallint",length=3,unique=true,options={"unsigned":true})
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* one brands has many models
*
* @ORM\OneToMany(targetEntity="Models", mappedBy="brandId")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
/**
* @ORM\Column(type="string", length=25)
*/
private $brand;
.......
}
Models
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\ModelsRepository")
* @ORM\Table(name="models")
*/
class Models
{
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(type="smallint",length=4,unique=true,options={"unsigned":true})
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=25)
*/
private $model;
/**
* Many models for one brand
* @ORM\ManyToOne(targetEntity="Brands",inversedBy="models")
* @ORM\JoinColumn(name="brand_id", referencedColumnName="id")
*/
private $brandId;
/**
* Many models for one segment
* @ORM\ManyToOne(targetEntity="Segments", inversedBy="models")
* @ORM\JoinColumn(name="segment_id", referencedColumnName="id")
*/
private $segmentId;
.....
}
Upvotes: 0
Reputation: 2030
A valid and clean entity mapping should be something like:
Brand.php
/**
* @ORM\Entity
* @ORM\Table(name="brands")
*/
class Brand
{
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* one brands has many models
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Model", mappedBy="brand")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
}
Model.php
class Model
{
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\Column(type="string", length=25)
*/
private $name;
/**
* Many models for one brand
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Brand",inversedBy="models")
*/
private $brand;
}
for clean and easy usage:
$brand->getId(); //get id of brand
$brand->getModels(); //get array of Model object, ArrayCollection
$model->getBrand()->getId(); // Get id of related brand of some model
$model->getBrand()->getName(); //get the name of other propery of related brand
Upvotes: 1
Reputation: 2232
Wrong answer removed...
Bonus tips: Entity classes or better their instances should represent single datasets of a table. So their names should be singular ;) By chosing not prefixed names for your primary key columns, you can spare some code, because Doctrine can work its magic then. Also you should not prefix one column with the table name, if you do not prefix all of them.
Upvotes: 0
Reputation: 41810
In your Brands
model, this annotation should not be present.
* @ORM\JoinColumn(name="brandId", referencedColumnName="brandId")
JoinColumn
only applies to ManyToOne
and OneToOne
fields. This is because in a one to many relationship, there will not be a join column in the table that contains the data for the owning ("one") side of the relationship.
JoinColumn
is for defining a column on the "many" side that identifies which record on the "one" side owns it, so including it in the Models
model is okay.
Upvotes: 1