Fran Soriano
Fran Soriano

Reputation: 25

Doctrine - How to create inverse relation?

In symfony I created two entities from a database already created. I used the following commands from the console of symfony:

php app/console doctrine:mapping:import --force IDFrontendBundle xml
php app/console doctrine:mapping:convert annotation ./src
php app/console doctrine:generate:entities IDFrontendBundle

Two of the entities that generate me and where I have the problem are as follows

use Doctrine\ORM\Mapping as ORM;

/**
 * ProviderRate
 *
 * @ORM\Table(name="provider_rate", indexes={@ORM\Index(name="fk_proveedor_has_producto_compra_producto_compra1_idx", columns={"product_id"}), @ORM\Index(name="fk_id_tarifa_proveedor_id_moneda1_idx", columns={"currency_id"}), @ORM\Index(name="IDX_3A645C45A53A8AA", columns={"provider_id"})})
 * @ORM\Entity(repositoryClass="IDavid\FrontendBundle\Entity\ProviderRateRepository")
 */
class ProviderRate
{
/**
 * @var string
 *
 * @ORM\Column(name="reference", type="string", length=45, nullable=false)
 */
private $reference;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=45, nullable=false)
 */
private $name;

/**
 * @var string
 *
 * @ORM\Column(name="description", type="string", length=255, nullable=false)
 */
private $description;

/**
 * @var integer
 *
 * @ORM\Column(name="amount_per_unit", type="integer", nullable=true)
 */
private $amountPerUnit;

/**
 * @var string
 *
 * @ORM\Column(name="unit_price", type="decimal", precision=25, scale=3, nullable=false)
 */
private $unitPrice;

/**
 * @var string
 *
 * @ORM\Column(name="discount", type="decimal", precision=25, scale=3, nullable=false)
 */
private $discount;

/**
 * @var \IDavid\FrontendBundle\Entity\Providers
 *
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="NONE")
 * @ORM\OneToOne(targetEntity="IDavid\FrontendBundle\Entity\Providers")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="provider_id", referencedColumnName="id")
 * })
 */
private $provider;

/**
 * @var \IDavid\FrontendBundle\Entity\Products
 *
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="NONE")
 * @ORM\OneToOne(targetEntity="IDavid\FrontendBundle\Entity\Products")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="product_id", referencedColumnName="id")
 * })
 */
private $product;

/**
 * @var \IDavid\FrontendBundle\Entity\Currencies
 *
 * @ORM\ManyToOne(targetEntity="IDavid\FrontendBundle\Entity\Currencies")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="currency_id", referencedColumnName="id")
 * })
 */
private $currency;

and

use Doctrine\ORM\Mapping as ORM;

/**
 * Products
 *
 * @ORM\Table(name="products", uniqueConstraints={@ORM\UniqueConstraint(name="id_producto_UNIQUE", columns={"id"})}, indexes={@ORM\Index(name="fk_id_productos_id_categorias1_idx", columns={"category_id"}), @ORM\Index(name="fk_id_productos_id_producto_tipo1_idx", columns={"type"}), @ORM\Index(name="fk_id_productos_id_moneda1_idx", columns={"currency_id"})})
 * @ORM\Entity(repositoryClass="IDavid\FrontendBundle\Entity\ProductsRepository")
 */
class Products
{
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=45, nullable=false)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="string", length=255, nullable=false)
     */
    private $description;

    /**
     * @var string
     *
     * @ORM\Column(name="code", type="string", length=45, nullable=false)
     */
    private $code;

    /**
     * @var string
     *
     * @ORM\Column(name="description_long", type="text", nullable=false)
     */
    private $descriptionLong;

    /**
     * @var integer
     *
     * @ORM\Column(name="amount_per_unit", type="integer", nullable=false)
     */
    private $amountPerUnit;

    /**
     * @var string
     *
     * @ORM\Column(name="weight", type="decimal", precision=11, scale=3, nullable=false)
     */
    private $weight;

    /**
     * @var string
     *
     * @ORM\Column(name="web", type="string", length=100, nullable=false)
     */
    private $web;

    /**
     * @var boolean
     *
     * @ORM\Column(name="isActive", type="boolean", nullable=false)
     */
    private $isactive;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="createdtime", type="datetime", nullable=false)
     */
    private $createdtime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="modifiedtime", type="datetime", nullable=false)
     */
    private $modifiedtime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="deletedtime", type="datetime", nullable=true)
     */
    private $deletedtime;

    /**
     * @var boolean
     *
     * @ORM\Column(name="isDeleted", type="boolean", nullable=false)
     */
    private $isdeleted;

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var \IDavid\FrontendBundle\Entity\Categories
     *
     * @ORM\ManyToOne(targetEntity="IDavid\FrontendBundle\Entity\Categories")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     * })
     */
    private $category;

    /**
     * @var \IDavid\FrontendBundle\Entity\ProductTypes
     *
     * @ORM\ManyToOne(targetEntity="IDavid\FrontendBundle\Entity\ProductTypes")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="type", referencedColumnName="id")
     * })
     */
    private $type;

    /**
     * @var \IDavid\FrontendBundle\Entity\Currencies
     *
     * @ORM\ManyToOne(targetEntity="IDavid\FrontendBundle\Entity\Currencies")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="currency_id", referencedColumnName="id")
     * })
     */
    private $currency;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="IDavid\FrontendBundle\Entity\Sets", inversedBy="product")
     * @ORM\JoinTable(name="products_sets",
     *   joinColumns={
     *     @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="set_id", referencedColumnName="id")
     *   }
     * )
     */
    private $set;

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="IDavid\FrontendBundle\Entity\Products", mappedBy="productParentid")
 */
private $product;

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="IDavid\FrontendBundle\Entity\Documents", inversedBy="product")
 * @ORM\JoinTable(name="product_attachments",
 *   joinColumns={
 *     @ORM\JoinColumn(name="product_id", referencedColumnName="id")
 *   },
 *   inverseJoinColumns={
 *     @ORM\JoinColumn(name="document_id", referencedColumnName="id")
 *   }
 * )
 */
private $document;

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="IDavid\FrontendBundle\Entity\Images", inversedBy="product")
 * @ORM\JoinTable(name="products_images",
 *   joinColumns={
 *     @ORM\JoinColumn(name="product_id", referencedColumnName="id")
 *   },
 *   inverseJoinColumns={
 *     @ORM\JoinColumn(name="image_id", referencedColumnName="id")
 *   }
 * )
 */
private $image;

 /**
     * Constructor
     */
    public function __construct()
    {
        $this->set = new \Doctrine\Common\Collections\ArrayCollection();
        $this->product = new \Doctrine\Common\Collections\ArrayCollection();
        $this->document = new \Doctrine\Common\Collections\ArrayCollection();
        $this->image = new \Doctrine\Common\Collections\ArrayCollection();
        $this->providerRate = new \Doctrine\Common\Collections\ArrayCollection();
    }

I tried creating a new variable to join the two tables in reverse order into the product class

/**
 * @ORM\OneToMany(targetEntity="IDavid\FrontendBundle\Entity\ProviderRate", inversedBy="product")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="id", referencedColumnName="product_id")
 * })
 */
private $providerRate;

But when I make a DQL query, symfony tells me that there is no association. Is there any way to do this?

$dql = "SELECT p, pr FROM IDFrontendBundle:Products p
                        JOIN p.providerRate pr";
$query = $this->getEntityManager()->createQuery($dql);

Upvotes: 1

Views: 1527

Answers (1)

Jovan Perovic
Jovan Perovic

Reputation: 20201

You relationship cardinality is different on each side.

ProviderRate -> Product (OneToOne)
Product -> ProviderRate (OneToMany)

As such, it won't work. OneToOne should be on both sides or, OneToMany should be paired with ManyToOne.

I assume the following:

  • One Product can has multiple ProviderRates. It that correct?

If so, you need:

ProviderRate class

/**
 * @var \IDavid\FrontendBundle\Entity\Products
 *
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="NONE")
 * @ORM\ManyToOne(targetEntity="IDavid\FrontendBundle\Entity\Products", mappedBy="providerRate")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="product_id", referencedColumnName="id")
 * })
 */
private $product;

Products class

/**
 * @ORM\OneToMany(targetEntity="IDavid\FrontendBundle\Entity\ProviderRate", inversedBy="product")
 */
private $providerRate;

As you can see, once you declase @JoinColums on either of relationshp's sides, there is no need to specify one on other side. Also, inversedBy should be matched by mappedBy.

Does this help?

EDIT

Change mappedBy and inversedBy attribute order.

ProviderRate class

/**
 * @var \IDavid\FrontendBundle\Entity\Products
 *
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="NONE")
 * @ORM\ManyToOne(targetEntity="IDavid\FrontendBundle\Entity\Products", inversedBy="providerRate")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="product_id", referencedColumnName="id")
 * })
 */
private $product;

Products class

/**
 * @ORM\OneToMany(targetEntity="IDavid\FrontendBundle\Entity\ProviderRate", mappedBy="product")
 */
private $providerRate;

Upvotes: 2

Related Questions