web-dev-qa-db-fra.com

Doctrine 2 et table de liens Plusieurs à plusieurs avec un champ supplémentaire

(Désolé pour ma question incohérente: j'ai essayé de répondre à quelques questions alors que j'écrivais ce billet, mais le voici :)

J'essaie de créer un modèle de base de données avec une relation plusieurs à plusieurs dans une table de liens, mais qui a également une valeur par lien, dans ce cas une table de gestion des stocks. (Ceci est un exemple de base pour plus de problèmes que j'ai, mais je pensais que je devrais simplement le tester avec ceci avant de continuer).

Database model for a basic multi-store, multi-product store-keeping system

J'ai utilisé exportmwb pour générer le magasin et le produit Entities pour cet exemple simple. Les deux sont affichés ci-dessous.

Cependant, le problème est que je ne vois pas comment accéder à la valeur stock.amount (signé int, car il peut être négatif) à l'aide de Doctrine. Aussi, quand j'essaie de créer les tables en utilisant la doctrine orm: schema-tool: create de doctrine

the database layout as it is seen from HeidiSQL

Cela n'a donné que deux entités et trois tables, une sous forme de table de liens sans valeurs et deux tables de données, car les relations plusieurs à plusieurs ne sont pas des entités elles-mêmes et je ne peux donc avoir que Product et Store en tant qu'entité.

Donc, logiquement, j'ai essayé de changer mon modèle de base de données pour que stock soit une table séparée avec des relations entre stocker et produit. J'ai aussi réécrit les noms de champs juste pour pouvoir exclure cela en tant que source du problème:

changed database layout

Ensuite, j'ai découvert que je n'avais toujours pas d'entité Stock ... et que la base de données elle-même n'avait pas de champ "montant".

J'avais vraiment besoin de pouvoir lier ces magasins et ces produits dans une table de stock (entre autres choses) ... il ne suffit donc pas d'ajouter du stock au produit lui-même.

root@hdev:/var/www/test/library# php doctrine.php orm:info
Found 2 mapped entities:
[OK]   Entity\Product
[OK]   Entity\Store

Et lorsque je crée la base de données, elle ne me donne toujours pas les bons champs dans la table stock:

the database layout as it is seen from HeidiSQL

Alors, en regardant certaines choses ici, j'ai découvert que les connexions plusieurs à plusieurs ne sont pas des entités et ne peuvent donc pas avoir de valeurs. J'ai donc essayé de le changer en une table séparée avec des relations avec les autres, mais cela n'a toujours pas fonctionné.

Qu'est-ce que je fais mal ici?

84
Henry van Megen

Une association plusieurs-à-plusieurs avec des valeurs supplémentaires n'est pas un multiple-à-plusieurs, mais bien une nouvelle entité, puisqu'elle dispose désormais d'un identifiant (les deux relations avec les entités connectées) et de valeurs.

C'est aussi la raison pour laquelle les associations Plusieurs-À-Plusieurs sont si rares: vous avez tendance à y stocker des propriétés supplémentaires, telles que sorting, amount, etc.

Ce dont vous avez probablement besoin, c’est de l’ordre suivant (j’ai rendu les deux relations bidirectionnelles, envisagez d’en faire au moins une unidirectionnelle):

Produit:

namespace Entity;

use Doctrine\ORM\Mapping as ORM;

/** @ORM\Table(name="product") @ORM\Entity() */
class Product
{
    /** @ORM\Id() @ORM\Column(type="integer") */
    protected $id;

    /** ORM\Column(name="product_name", type="string", length=50, nullable=false) */
    protected $name;

    /** @ORM\OneToMany(targetEntity="Entity\Stock", mappedBy="product") */
    protected $stockProducts;
}

Le magasin:

namespace Entity;

use Doctrine\ORM\Mapping as ORM;

/** @ORM\Table(name="store") @ORM\Entity() */
class Store
{
    /** @ORM\Id() @ORM\Column(type="integer") */
    protected $id;

    /** ORM\Column(name="store_name", type="string", length=50, nullable=false) */
    protected $name;

    /** @ORM\OneToMany(targetEntity="Entity\Stock", mappedBy="store") */
    protected $stockProducts;
}

Stock:

namespace Entity;

use Doctrine\ORM\Mapping as ORM;

/** @ORM\Table(name="stock") @ORM\Entity() */
class Stock
{
    /** ORM\Column(type="integer") */
    protected $amount;

    /** 
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="Entity\Store", inversedBy="stockProducts") 
     * @ORM\JoinColumn(name="store_id", referencedColumnName="id", nullable=false) 
     */
    protected $store;

    /** 
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="Entity\Product", inversedBy="stockProducts") 
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id", nullable=false) 
     */
    protected $product;
}
135
Ocramius

Doctrine gère très bien les relations plusieurs à plusieurs.

Le problème que vous rencontrez est que vous n'avez pas besoin d'une simple association ManyToMany, car les associations ne peuvent pas avoir de données "supplémentaires".

Votre table intermédiaire (stock), car elle contient plus que product_id et store_id, a besoin de sa propre entité pour modéliser ces données supplémentaires.

Donc, vous voulez vraiment trois classes d'entité:

  • Produit
  • StockLevel
  • Le magasin

et deux associations:

  • Produit unToMany StockLevel
  • Magasin oneToMany StockLevel
17
timdev