หลักคำสอน 2 และตารางลิงก์แบบกลุ่มต่อกลุ่มพร้อมช่องเสริม


88

(ขออภัยสำหรับคำถามที่ไม่ต่อเนื่องกัน: ฉันพยายามตอบคำถามในขณะที่เขียนโพสต์นี้ แต่นี่คือ :)

ฉันกำลังพยายามสร้างแบบจำลองฐานข้อมูลที่มีความสัมพันธ์แบบกลุ่มต่อกลุ่มภายในตารางลิงก์ แต่ก็มีค่าต่อลิงก์เช่นกันในกรณีนี้คือตารางเก็บสต็อค (นี่เป็นตัวอย่างพื้นฐานสำหรับปัญหาอื่น ๆ ที่ฉันประสบ แต่ฉันคิดว่าจะทดสอบกับสิ่งนี้ก่อนที่จะดำเนินการต่อ)

แบบจำลองฐานข้อมูลสำหรับระบบการเก็บรักษาผลิตภัณฑ์หลายร้านขั้นพื้นฐาน

ฉันใช้exportmwbเพื่อสร้าง Entities Store และ Product สองรายการสำหรับตัวอย่างง่ายๆนี้ทั้งสองอย่างจะแสดงด้านล่าง

อย่างไรก็ตามปัญหาตอนนี้คือฉันไม่สามารถหาวิธีเข้าถึงค่า stock.amount (ลงนาม int เนื่องจากอาจเป็นค่าลบ) โดยใช้ Doctrine นอกจากนี้เมื่อฉันพยายามสร้างตารางโดยใช้ orm ของหลักคำสอน: schema-tool: create function

เค้าโครงฐานข้อมูลตามที่เห็นจาก HeidiSQL

สิ่งนี้ให้ผลลัพธ์เพียงสองเอนทิตีและสามตารางหนึ่งเป็นตารางลิงก์ที่ไม่มีค่าและตารางข้อมูลสองตารางเนื่องจากความสัมพันธ์แบบกลุ่มต่อกลุ่มไม่ใช่เอนทิตีในตัวเองดังนั้นฉันจึงมีได้เฉพาะผลิตภัณฑ์และร้านค้าเป็นเอนทิตี

ด้วยเหตุนี้ฉันจึงลองเปลี่ยนโมเดลฐานข้อมูลของฉันให้มีสต็อกเป็นตารางแยกต่างหากที่มีความสัมพันธ์กับการจัดเก็บและผลิตภัณฑ์ ฉันยังเขียนชื่อเขตข้อมูลใหม่เพื่อให้สามารถยกเว้นว่าเป็นที่มาของปัญหา:

เปลี่ยนเค้าโครงฐานข้อมูล

จากนั้นสิ่งที่ฉันพบก็คือฉันยังไม่ได้รับ Stock entity ... และฐานข้อมูลเองก็ไม่มีฟิลด์ 'amount'

ฉันต้องการที่จะผูกร้านค้าและสินค้าเหล่านี้เข้าด้วยกันในตารางสต็อค (เหนือสิ่งอื่นใด) ...

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

และเมื่อฉันสร้างฐานข้อมูลก็ยังไม่ได้ให้ฟิลด์ที่ถูกต้องในตารางหุ้น:

เค้าโครงฐานข้อมูลตามที่เห็นจาก HeidiSQL

ดังนั้นเมื่อค้นหาบางสิ่งที่นี่ฉันพบว่าการเชื่อมต่อแบบกลุ่มต่อกลุ่มไม่ใช่เอนทิตีดังนั้นจึงไม่มีค่า ฉันจึงลองเปลี่ยนเป็นตารางแยกต่างหากที่มีความสัมพันธ์กับคนอื่น ๆ แต่ก็ยังไม่ได้ผล

ฉันทำอะไรผิดที่นี่?


โอเคฉันพบคำพูดสองสามข้อที่ระบุว่าเป็นไปไม่ได้ที่จะมีการเชื่อมต่อแบบหลายต่อหลายคนโดยใช้หลักคำสอนโดยมีข้อคิดเห็นที่แนะนำให้ป้องกันความสัมพันธ์เหล่านี้ .. แต่จะเป็นอย่างไรถ้าคุณติดอยู่กับสถานการณ์เช่นที่ฉันอธิบายไว้ใน คำถามเดิมของฉัน? ฉันมีฐานข้อมูลทั้งหมดที่เข้ากันได้กับ Magento ซึ่งอาศัยความสัมพันธ์แบบกลุ่มต่อกลุ่มอย่างสมบูรณ์ โดยพื้นฐานแล้วฉันถูกบอกว่า "Doctrine ORM can't handle many-to-many, don't use it" ??
Henry van Megen


3
จะให้ +100 ถ้าฉันทำได้สำหรับความพยายามที่คุณทำเพื่ออธิบายสิ่งที่ฉันสงสัยในวิธีที่ดี :-)
Torsten Römer

คำตอบ:


143

การเชื่อมโยงแบบกลุ่มต่อกลุ่มกับค่าเพิ่มเติมไม่ใช่แบบกลุ่มต่อกลุ่มจำนวนมาก แต่เป็นเอนทิตีใหม่เนื่องจากตอนนี้มีตัวระบุ (ความสัมพันธ์ทั้งสองกับเอนทิตีที่เชื่อมโยงกัน) และค่า

นั่นเป็นเหตุผลที่ว่าทำไมสมาคมหลายต่อหลายคนที่หายากเพื่อให้คุณมีแนวโน้มที่จะจัดเก็บคุณสมบัติเพิ่มเติมในพวกเขาเช่นsorting, amountฯลฯ

สิ่งที่คุณอาจต้องการมีดังต่อไปนี้ (ฉันสร้างความสัมพันธ์ทั้งสองทิศทางแบบสองทิศทางให้พิจารณาสร้างอย่างน้อยหนึ่งในทิศทางเดียว):

สินค้า:

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

เก็บ:

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

คลังสินค้า:

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

ตกลงฉันจะเพิ่ม getter และ setters เพราะด้วยการตั้งค่านี้ฉันจะได้รับคีย์หลักเท่านั้นและทำงานโดยไม่มีค่าใด ๆ :)
Henry van Megen

เมื่อฉันใช้การตั้งค่านี้แล้วลองสอบถามโดยใช้ Stock.store_id ฉันได้รับข้อผิดพลาด "Stock ไม่มีฟิลด์หรือการเชื่อมโยงชื่อ store_id" ควรพบเนื่องจากคอลัมน์มีอยู่ในฐานข้อมูล
afilina

@afilina ฐานข้อมูลไม่สำคัญในขณะที่สร้างสคีมา - DBAL โยนข้อยกเว้นเนื่องจากไม่พบคอลัมน์ในข้อมูลเมตา DDL (ในหน่วยความจำ)
Ocramius

@Ocramius สิ่งที่ฉันหมายถึงคือ DB ถูกสร้างขึ้นจากข้อมูลเมตา SIf สามารถสร้างคอลัมน์ได้ตั้งแต่แรกจากนั้นควรจะสามารถค้นหาได้ในระหว่างการสืบค้น วิธีแก้ปัญหาของฉันคือเปรียบเทียบ Stock.store กับ id ที่ต้องการ
afilina

100% สิ่งที่ฉันต้องการและใช้งานได้เหมือนมีเสน่ห์! คุณรู้วิธีสร้างแบบฟอร์มด้วย fieldset เพื่อแก้ไขจำนวนเงินต่อร้านค้าและสินค้าหรือไม่?
cwhisperer

17

หลักคำสอนจัดการกับความสัมพันธ์แบบกลุ่มต่อกลุ่มได้ดี

ปัญหาที่คุณพบคือคุณไม่จำเป็นต้องมีการเชื่อมโยง ManyToMany แบบง่ายๆเนื่องจากการเชื่อมโยงไม่สามารถมีข้อมูล "พิเศษ" ได้

ตารางกลาง (สต็อค) ของคุณเนื่องจากมีมากกว่า product_id และ store_id จึงจำเป็นต้องมีเอนทิตีของตัวเองในการจำลองข้อมูลเพิ่มเติมนั้น

ดังนั้นคุณต้องการเอนทิตีสามคลาส:

  • สินค้า
  • StockLevel
  • เก็บ

และสองสมาคม:

  • สินค้า oneToMany StockLevel
  • จัดเก็บ oneToMany StockLevel

1
ขอบคุณสำหรับคำตอบ ! ฉันได้เพิ่มช่องพิเศษในตารางเช่น "หุ้น" ของฉัน อย่างไรก็ตามหลักคำสอนยังไม่พิจารณา "join table" นี้และข้ามไปเมื่อฉันเรียกใช้php app/console doctrine:mapping:import AppBundle ymlเพื่อนำเข้าสคีมาจากฐานข้อมูล ฉันต้องการให้สร้างไฟล์ yaml การแมปพิเศษนี้ ใครมีความคิดบ้าง? :(
Stphane

คำตอบไม่ได้แก้ไขข้อมูลการเขียนไปยังเอนทิตี "การเชื่อมต่อ" นี่คือปัญหา. ไม่ประกาศเอนทิตี กรุณาช่วยสนับสนุนตัวอย่างที่ข้อมูลถูกส่งจากฟอร์ม (ฟิลด์ CollectionType มีแบบฟอร์มที่ฝังอยู่กับฟิลด์ EntityType) ฉันไม่สามารถส่งผ่านข้อมูลจากฟอร์ม
ฝัง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.