web-dev-qa-db-ja.com

Doctrine 2および追加フィールドを持つ多対多リンクテーブル

(矛盾した質問でごめんなさい:この投稿を書いているときにいくつかの質問に答えようとしましたが、ここにあります:)

リンクテーブル内に多対多の関係を持つデータベースモデルを作成しようとしていますが、リンクごとの値もあります。この場合は在庫管理テーブルです。 (これは私が抱えているより多くの問題の基本的な例ですが、続行する前にこれでテストするだけだと思いました)。

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

exportmwb を使用して、この簡単な例の2つのエンティティストアと製品を生成しました。両方を以下に表示します。

ただし、今の問題は、Doctrineを使用してstock.amount値(負の値になる可能性があるため、signed int)にアクセスする方法がわからないことです。また、Doctrineのorm:schema-tool:create関数を使用してテーブルを作成しようとすると

the database layout as it is seen from HeidiSQL

多対多のリレーションシップはエンティティ自体ではないため、エンティティと製品とストアのみを持つことができるため、2つのエンティティと3つのテーブル(値のないリンクテーブルと2つのデータテーブル)のみが生成されました。

そのため、論理的には、データベースモデルを変更して、在庫をストアと製品との関係を持つ別のテーブルとして持つようにしました。また、問題の原因としてそれを除外できるように、フィールド名を書き直しました。

changed database layout

それから私が見つけたのは、まだ株式エンティティを取得していないということです...そして、データベース自体には「金額」フィールドがありませんでした。

これらの店舗と製品を(特に)在庫テーブルにバインドできるようにする必要がありました。そのため、製品自体に在庫を追加するだけでは選択肢になりません。

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

また、データベースを作成するときに、ストックテーブルに正しいフィールドが表示されません。

the database layout as it is seen from HeidiSQL

そこで、ここでいくつかのことを調べてみると、多対多の接続はエンティティではないため、値を持つことができないことがわかりました。そこで、他のテーブルとの関係を持つ別のテーブルに変更しようとしましたが、それでもうまくいきませんでした。

ここで何が間違っていますか?

84
Henry van Megen

追加の値との多対多の関連付けは多対多ではなく、識別子(接続されたエンティティへの2つの関係)と値を持っているため、実際には新しいエンティティです。

多対多の関連付けが非常にまれな理由でもあります。sortingamountなどの追加のプロパティを保存する傾向があります。

おそらく必要なのは、次のようなものです(両方の関係を双方向にし、少なくとも一方を単方向にすることを検討してください):

製品:

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

Doctrineは多対多の関係をうまく処理します。

あなたが持っている問題は、アソシエーションが「余分な」データを持つことができないため、単純なManyToManyアソシエーションを必要としないことです。

中間(ストック)テーブルはproduct_idとstore_idを超えて含まれているため、その追加データをモデル化するために独自のエンティティが必要です。

したがって、3つのクラスのエンティティが本当に必要です。

  • 製品
  • 在庫量
  • 格納

および2つの関連付け:

  • 商品oneToMany StockLevel
  • OneToMany StockLevelを保存する
17
timdev