Lehre 2 und Viele-zu-Viele-Verknüpfungstabelle mit einem zusätzlichen Feld

86

(Entschuldigung für meine inkohärente Frage: Ich habe versucht, einige Fragen zu beantworten, als ich diesen Beitrag schrieb, aber hier ist es :)

Ich versuche, ein Datenbankmodell mit einer Viele-zu-Viele-Beziehung innerhalb einer Verknüpfungstabelle zu erstellen, das jedoch auch einen Wert pro Verknüpfung aufweist, in diesem Fall eine Lagertabelle. (Dies ist ein grundlegendes Beispiel für weitere Probleme, die ich habe, aber ich dachte, ich würde es nur damit testen, bevor ich fortfahre).

Datenbankmodell für ein grundlegendes System zur Aufbewahrung mehrerer Geschäfte und Produkte

Ich habe exportmwb verwendet , um die beiden Entities Store und Product für dieses einfache Beispiel zu generieren. Beide werden unten angezeigt.

Das Problem ist jetzt jedoch, dass ich nicht herausfinden kann, wie ich mit Doctrine auf den stock.amount-Wert (signiert int, da er negativ sein kann) zugreifen kann. Auch wenn ich versuche, die Tabellen mit der Funktion orm: schema-tool: create der Doktrin zu erstellen

das Datenbanklayout, wie es von HeidiSQL aus gesehen wird

Dies ergab nur zwei Entitäten und drei Tabellen, eine als Verknüpfungstabelle ohne Werte und zwei Datentabellen, da viele-zu-viele-Beziehungen selbst keine Entitäten sind, sodass ich nur Produkt und Speicher als Entität haben kann.

Daher habe ich logischerweise versucht, mein Datenbankmodell so zu ändern, dass der Bestand als separate Tabelle mit Beziehungen zu Speicher und Produkt vorhanden ist. Ich habe auch die Feldnamen umgeschrieben, um dies als Ursache des Problems ausschließen zu können:

Datenbanklayout geändert

Dann stellte ich fest, dass ich immer noch keine Aktienentität bekam ... und die Datenbank selbst kein 'Betrag'-Feld hatte.

Ich musste wirklich in der Lage sein, diese Geschäfte und Produkte (unter anderem) in einer Lagertabelle zusammenzubinden. Es ist also keine Option, nur den Lagerbestand des Produkts selbst hinzuzufügen.

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

Und wenn ich die Datenbank erstelle, werden mir immer noch nicht die richtigen Felder in der Bestandsliste angezeigt:

das Datenbanklayout, wie es von HeidiSQL aus gesehen wird

Als ich hier einige Dinge nachschlug, stellte ich fest, dass viele-zu-viele-Verbindungen keine Entitäten sind und daher keine Werte haben können. Also habe ich versucht, es in eine separate Tabelle mit Beziehungen zu den anderen zu ändern, aber es hat immer noch nicht funktioniert.

Was mache ich hier falsch?

Henry van Megen
quelle
Ok, ich habe ein paar Erwähnungen gefunden, die besagen, dass es mit Doctrine nicht möglich ist, viele-zu-viele-Verbindungen herzustellen. In Kommentaren wird empfohlen, diese Beziehungen zu verhindern. Aber was ist, wenn Sie wirklich in einer Situation wie der von mir beschriebenen stecken bleiben? meine ursprüngliche Frage? Ich habe eine komplette Datenbank, die mit Magento kompatibel ist und sich vollständig auf viele-zu-viele-Beziehungen stützt. Im Grunde wird mir gesagt, dass "Doctrine ORM nicht mit vielen zu vielen umgehen kann, benutze es nicht"?
Henry van Megen
3
Ich würde dir +100 geben, wenn ich für die Mühe, die du gemacht hast, genau erklären könnte, worüber ich mich so schön gewundert habe :-)
Torsten Römer

Antworten:

139

Eine Viele-zu-Viele-Zuordnung mit zusätzlichen Werten ist keine Viele-zu-Viele-Zuordnung, sondern eine neue Entität, da sie jetzt eine Kennung (die beiden Beziehungen zu den verbundenen Entitäten) und Werte aufweist.

Das ist auch der Grund , warum viele-zu-Viele Verbände sind so selten: Sie neigen dazu , in ihnen zusätzliche Eigenschaften zu speichern, wie sorting, amountetc.

Was Sie wahrscheinlich brauchen, ist etwa Folgendes (ich habe beide Beziehungen bidirektional gemacht, erwägen Sie, mindestens eine davon unidirektional zu machen):

Produkt:

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

Geschäft:

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

Lager:

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;
}
Ocramius
quelle
Ok, ich werde einige Getter und Setter hinzufügen, da ich mit diesem Setup nur die Primärschlüssel ohne Werte zum Laufen bringe :)
Henry van Megen
Wenn ich dieses Setup verwende und dann versuche, mit Stock.store_id abzufragen, wird die Fehlermeldung "Stock hat kein Feld oder keine Zuordnung mit dem Namen store_id" angezeigt. Es sollte gefunden werden, da die Spalte in der Datenbank vorhanden ist.
Afilina
@afilina die Datenbank spielt beim Generieren des Schemas keine Rolle - die DBAL löst die Ausnahme aus, weil sie die Spalte in den DDL-Metadaten (im Speicher) nicht findet
Ocramius
@Ocramius Was ich meinte war, dass die DB aus Metadaten generiert wurde. Wenn es in der Lage war, die Spalte überhaupt zu generieren, sollte es in der Lage sein, sie während der Abfrage zu finden. Die Lösung für mein Problem bestand darin, Stock.store mit der gewünschten ID zu vergleichen.
Afilina
100% was ich brauche und es funktioniert wie ein Zauber! Wissen Sie, wie Sie ein Formular mit Fieldset erstellen, um die Menge pro Geschäft und Produkt zu bearbeiten?
Whisperer
17

Die Lehre geht gut mit vielen-zu-vielen-Beziehungen um.

Das Problem, das Sie haben, ist, dass Sie keine einfache ManyToMany-Zuordnung benötigen, da Zuordnungen keine "zusätzlichen" Daten enthalten können.

Ihre mittlere (Lager-) Tabelle benötigt eine eigene Entität, um diese zusätzlichen Daten zu modellieren, da sie mehr als product_id und store_id enthält.

Sie möchten also wirklich drei Entitätsklassen:

  • Produkt
  • StockLevel
  • Geschäft

und zwei Verbände:

  • Produkt oneToMany StockLevel
  • Speichern Sie oneToMany StockLevel
timdev
quelle
1
Vielen Dank für Ihre Antwort ! Ich habe meiner "stock" -ähnlichen Tabelle zusätzliche Felder hinzugefügt. Die Doktrin berücksichtigt diese "Join-Tabelle" jedoch immer noch nicht und überspringt sie, wenn ich sie php app/console doctrine:mapping:import AppBundle ymlausführe, um das Schema aus der Datenbank zu importieren. Ich möchte, dass diese zusätzliche Mapping-Yaml-Datei generiert wird. Hat jemand eine Idee? :(
Stphane
Antwort: Das Schreiben von Daten in die Entität "Verbindung" wird nicht aufgelöst. Das ist ein Problem. Entitäten nicht deklarieren. Kann bitte jemand unterstützen, der ein Beispiel unterstützt, bei dem Daten aus dem Formular übergeben werden (das Feld CollectionType enthält ein eingebettetes Formular mit dem Feld EntityType). Ich kann keine Daten vom eingebetteten Formular an das Hauptformular übergeben und die
Feldsammlung