原则2和带有额外字段的多对多链接表

(对于我语无伦次的问题,我很抱歉: 在写这篇文章的时候,我试图回答一些问题,但是这里是:)

我试图在一个链接表中创建一个具有多对多关系的数据库模型,但是每个链接都有一个值,在本例中是一个库存表。(这是我遇到的更多问题的一个基本示例,但是我想在继续之前先用这个测试一下)。

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

我已经使用 出口为这个简单的示例生成了两个实体商店和产品,它们都显示在下面。

然而,现在的问题是,我不知道如何使用 Doctrine 访问 stock.amount 值(有符号 int,因为它可能是负数)。此外,当我尝试使用主义的 orm: schema-tool: create 函数创建表时

the database layout as it is seen from HeidiSQL

这只产生了两个实体和三个表,一个作为没有值的链接表和两个数据表,因为多对多关系本身不是实体,所以我只能将 Product 和 Store 作为一个实体。

因此,逻辑上,我尝试更改数据库模型,将 stock 作为一个单独的表,其中包含存储和产品的关系。我还重写了字段名,只是为了排除问题的根源:

changed database layout

然后我发现,我仍然没有得到一个股票实体... 和数据库本身没有一个’金额’-字段。

我真的需要能够绑定这些商店和产品在一起的股票表(在其他事情) ... 所以只是增加股票的产品本身不是一个选项。

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

当我创建数据库时,它仍然没有给出 stock 表中的正确字段:

the database layout as it is seen from HeidiSQL

所以,在这里查找一些东西,我发现多对多连接不是实体,因此不能有值。所以我试着把它改成一个单独的表,与其他表保持关系,但仍然没有用。

我做错了什么?

52897 次浏览

Doctrine handles many-to-many relationships just fine.

The problem that you're having is that you don't need a simple ManyToMany association, because associations can't have "extra" data.

Your middle (stock) table, since it contains more than product_id and store_id, needs its own entity to model that extra data.

So you really want three classes of entity:

  • Product
  • StockLevel
  • Store

and two associations:

  • Product oneToMany StockLevel
  • Store oneToMany StockLevel

A Many-To-Many association with additional values is not a Many-To-Many, but is indeed a new entity, since it now has an identifier (the two relations to the connected entities) and values.

That's also the reason why Many-To-Many associations are so rare: you tend to store additional properties in them, such as sorting, amount, etc.

What you probably need is something like following (I made both relations bidirectional, consider making at least one of them uni-directional):

Product:

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

Store:

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

Stock:

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