Доктрина 2 та таблиця посилань багато-до-багатьох із додатковим полем


88

(Вибачте за моє незв’язне запитання: я намагався відповісти на деякі запитання, коли писав цей пост, але ось він :)

Я намагаюся створити модель бази даних зі зв'язком "багато-до-багатьох" усередині таблиці посилань, але яка також має значення для кожного посилання, в даному випадку таблиці збереження запасів. (це базовий приклад для більшої кількості проблем, які у мене виникають, але я думав, що просто перевірю це на цьому, перш ніж продовжувати).

Модель бази даних для базової системи зберігання багатопродуктових магазинів

Я використав exportmwb для створення двох Entities Store і Product для цього простого прикладу, обидва відображені нижче.

Однак проблема зараз полягає в тому, що я не можу зрозуміти, як отримати доступ до значення stock.amount (підписаний int, оскільки це може бути негативно) за допомогою Doctrine. Крім того, коли я намагаюся створити таблиці, використовуючи функцію doctrine's orm: schema-tool: create

макет бази даних, як це видно з HeidiSQL

Це дало лише дві сутності та три таблиці, одну як таблицю посилань без значень та дві таблиці даних, оскільки відносини багато-до-багатьох не є сутностями, тому я можу мати лише Product і Store як сутність.

Отже, логічно, я спробував змінити модель бази даних, щоб мати запас як окрему таблицю з відносинами для зберігання та продукту. Я також переписав імена полів, щоб мати можливість виключити це як джерело проблеми:

змінений макет бази даних

Тоді я виявив, що я все ще не отримав сутність запасу ... і сама база даних не мала поля "сума".

Мені дійсно потрібно було зв’язати ці магазини та товари в таблиці запасів (крім іншого) ... так що просто додавати запас на сам товар не є варіантом.

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

І коли я створюю базу даних, вона все одно не дає мені правильних полів у таблиці запасів:

макет бази даних, як це видно з HeidiSQL

Отже, розглядаючи деякі речі тут, я виявив, що зв’язки «багато-до-багатьох» не є сутностями і, отже, не можуть мати значень. Тому я спробував змінити його на окрему таблицю зі зв’язками з іншими, але це все одно не спрацювало.

Що я тут роблю не так?


Гаразд, я знайшов пару згадок про те, що не можна мати багато-до-багатьох зв'язків, використовуючи Доктрину, з коментарями, що радять запобігати цим відносинам .. але що, якщо Ви справді застрягли в такій ситуації, як та, яку я описав у моє оригінальне запитання? У мене є ціла база даних, сумісна з Magento, яка повністю покладається на відносини багато-до-багатьох. Отже, в основному мені кажуть: "Доктрина ORM не може впоратися з багатьма-до-багатьох, не використовуй її" ??
Генрі ван Меген


3
Я б дав вам +100, якби я міг за ваші зусилля, щоб пояснити, про що саме я цікавився таким гарним способом :-)
Торстен Рьомер

Відповіді:


142

Асоціація "багато-до-багатьох" з додатковими значеннями не є "багато-до-багатьох", але насправді є новою суттю, оскільки тепер вона має ідентифікатор (два відношення до пов'язаних сутностей) і значення.

Це також причина , чому багато-до-багатьох асоціації настільки рідкісні , ви , як правило , зберігати додаткові властивості в них, наприклад 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;
}

Гаразд, я додам трохи геттера та сеттерів, тому що за допомогою цієї установки я отримую лише первинні ключі, які працюють без будь-яких значень :)
Генрі ван Меген

Коли я використовую це налаштування, а потім намагаюся зробити запит за допомогою Stock.store_id, я отримую помилку "Stock не має поля чи асоціації з ім'ям store_id". Його слід знайти, оскільки стовпець існує в базі даних.
afilina

@afilina db не має значення під час генерації схеми - DBAL видає виняток, оскільки не знаходить стовпець у метаданих DDL (в пам'яті)
Окрамій,

@Ocramius Я мав на увазі те, що БД була сформована з метаданих. Якщо йому вдалося спершу створити стовпець, тоді він міг би знайти його під час запиту. Рішенням моєї проблеми було порівняння Stock.store із бажаним ідентифікатором.
afilina

100% те, що мені потрібно, і це працює як шарм! Чи знаєте ви, як створити форму з набором полів, щоб відредагувати суму за магазин та товар?
cwhisperer

17

Доктрина чудово обробляє стосунки багато-до-багатьох.

Проблема у вас полягає в тому, що вам не потрібна проста асоціація ManyToMany, оскільки асоціації не можуть мати "зайвих" даних.

Вашій середній (запасній) таблиці, оскільки вона містить більше, ніж product_id та store_id, потрібна власна сутність для моделювання цих додаткових даних.

Отже, ви дійсно хочете три класи сутності:

  • Продукт
  • StockLevel
  • Зберігати

і дві асоціації:

  • Продукт один на багато запасів
  • Зберігайте oneToMany StockLevel

1
Спасибі за вашу відповідь ! Я додав додаткові поля до свого "запасу", як таблиця. Однак доктрина все ще не розглядає цю "таблицю об'єднань" і пропускає її під час запуску php app/console doctrine:mapping:import AppBundle yml, щоб імпортувати схему з бази даних. Я хотів би, щоб він створив цей додатковий файл зіставлення yaml. Хтось має якусь ідею? :(
Stphane

Відповідь не вирішує записування даних до сутності "з'єднання". Це проблема. Не декларує сутності. Чи може хтось порадувати приклад підтримки, де дані передаються з форми (поле CollectionType має вбудовану форму з полем EntityType). Я не можу передати дані із вбудованої форми в основну форму та правильно зберегти колекцію полів
zoore
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.