Doctrine 2 e tabella dei collegamenti molti-a-molti con un campo aggiuntivo


88

(Scusa per la mia domanda incoerente: ho provato a rispondere ad alcune domande mentre scrivevo questo post, ma eccolo :)

Sto cercando di creare un modello di database con una relazione molti-a-molti all'interno di una tabella di collegamento, ma che ha anche un valore per collegamento, in questo caso una tabella di magazzino. (questo è un esempio di base per più problemi che sto avendo, ma ho pensato di provarlo con questo prima di continuare).

Modello di database per un sistema di base per la conservazione dei punti vendita multiprodotto e multiprodotto

Ho usato exportmwb per generare i due Entities Store e Product per questo semplice esempio, entrambi sono visualizzati di seguito.

Tuttavia, il problema ora è che non riesco a capire come accedere al valore stock.amount (firmato int, poiché può essere negativo) usando Doctrine. Inoltre, quando provo a creare le tabelle usando la funzione orm: schema-tool: create di doctrine

il layout del database come si vede da HeidiSQL

Ciò ha prodotto solo due entità e tre tabelle, una come tabella di collegamento senza valori e due tabelle di dati, poiché le relazioni molti-a-molti non sono entità stesse, quindi posso avere solo Prodotto e Negozio come entità.

Quindi, logicamente, ho provato a cambiare il mio modello di database per avere lo stock come tabella separata con relazioni da memorizzare e prodotto. Ho anche riscritto i nomi dei campi solo per poterlo escludere come fonte del problema:

ha cambiato il layout del database

Quindi quello che ho scoperto è che non ho ancora ricevuto un'entità Stock ... e il database stesso non aveva un campo "importo".

Avevo davvero bisogno di essere in grado di legare questi negozi e prodotti insieme in una tabella delle scorte (tra le altre cose) ... quindi aggiungere semplicemente le scorte sul prodotto stesso non è un'opzione.

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

E quando creo il database, ancora non mi fornisce i campi corretti nella tabella delle scorte:

il layout del database come si vede da HeidiSQL

Quindi, cercando alcune cose qui, ho scoperto che le connessioni molti-a-molti non sono entità e quindi non possono avere valori. Quindi ho provato a cambiarlo in una tabella separata con relazioni con gli altri, ma ancora non ha funzionato.

Cosa sto facendo di sbagliato qui?


Ok, ho trovato un paio di menzioni che affermano che non è possibile avere connessioni molti-a-molti usando Doctrine, con commenti che consigliano di prevenire queste relazioni .. ma cosa succede se sei davvero bloccato con una situazione come quella che ho descritto in la mia domanda originale? Ho un intero database, compatibile con Magento, che si basa completamente su relazioni molti-a-molti. Quindi in pratica mi viene detto "Doctrine ORM non può gestire molti-a-molti, non usarlo" ??
Henry van Megen


3
Ti darei +100 se potessi per lo sforzo che hai fatto per spiegare esattamente quello che mi chiedevo in un modo così carino :-)
Torsten Römer

Risposte:


141

Un'associazione molti-a-molti con valori aggiuntivi non è un'entità molti-a-molti, ma è effettivamente una nuova entità, poiché ora ha un identificatore (le due relazioni con le entità connesse) e valori.

Questo è anche il motivo per cui le associazioni molti-a-molti sono così rare: tendi a memorizzare in esse proprietà aggiuntive, come sorting,amount e così via

Quello che probabilmente ti serve è qualcosa del tipo seguente (ho reso entrambe le relazioni bidirezionali, considera di renderne almeno una unidirezionale):

Prodotto:

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;
}

Negozio:

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;
}

Azione:

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;
}

Ok, aggiungerò alcuni getter e setter, perché con questa configurazione, ottengo solo le chiavi primarie attive e funzionanti senza alcun valore :)
Henry van Megen

Quando utilizzo questa configurazione e provo a interrogare utilizzando Stock.store_id, ottengo l'errore "Stock non ha un campo o un'associazione denominata store_id". Dovrebbe essere trovato perché la colonna esiste nel database.
afilina

@afilina il db non ha importanza durante la generazione dello schema - il DBAL lancia l'eccezione perché non trova la colonna nei metadati DDL (in memoria)
Ocramius

@Ocramius Quello che volevo dire era che il DB è stato generato dai metadati. Se è stato in grado di generare la colonna in primo luogo, dovrebbe essere in grado di trovarla durante la query. La soluzione al mio problema era confrontare Stock.store con l'id desiderato.
afilina

100% quello che mi serve e funziona a meraviglia! Sai come costruire un form con fieldset per modificare l'importo per negozio e prodotto?
cwhisperer

17

Dottrine gestisce bene le relazioni molti-a-molti.

Il problema che stai riscontrando è che non hai bisogno di una semplice associazione ManyToMany, perché le associazioni non possono avere dati "extra".

La tua tabella centrale (stock), poiché contiene più di product_id e store_id, necessita di una propria entità per modellare quei dati extra.

Quindi vuoi davvero tre classi di entità:

  • Prodotto
  • Livello delle scorte
  • Negozio

e due associazioni:

  • Prodotto oneToMany StockLevel
  • Memorizza oneToMany StockLevel

1
La ringrazio per la risposta ! Ho aggiunto campi extra alla mia tabella "stock". Tuttavia, doctrine continua a non considerare questa "tabella di join" e la salta quando eseguo php app/console doctrine:mapping:import AppBundle ymlper importare lo schema dal database. Vorrei che generasse questo file yaml di mappatura extra. Qualcuno ha qualche idea ? :(
Stphane

Risposta non risolvendo la scrittura dei dati nell'entità "connessione". Questo è un problema. Non dichiarare entità. Qualcuno può supportare l'esempio in cui i dati vengono passati dal modulo (il campo CollectionType ha un modulo incorporato con il campo EntityType). Non riesco a passare i dati dal modulo incorporato al modulo principale e salvare correttamente la raccolta di campi
zoore
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.