Doctrine 2和带有额外字段的多对多关联表

92

对于我的语无伦次的问题表示抱歉:当我写这篇帖子时,我试图回答一些问题,但现在问题来了:

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

基本多店铺、多商品库存系统的数据库模型

我已经使用exportmwb为这个简单的示例生成了两个实体 Store 和 Product,如下所示。

然而,问题现在是我无法弄清如何使用Doctrine访问stock.amount值(有符号整数,因为它可以是负数)。另外,当我尝试使用doctrine的orm:schema-tool:create函数创建表格时:

从HeidiSQL看到的数据库布局

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

因此,逻辑上,我尝试更改我的数据库模型,将stock作为与store和product有关系的独立表。 我还重新编写了字段名称,以便能够排除它作为问题来源:

更改后的数据库布局

然后我发现我仍然没有得到一个Stock实体...并且数据库本身也没有“amount”字段。

我真的需要能够在库存表中将这些商店和产品绑定在一起(除其他外)......因此,仅在产品本身上添加库存不是一个选项。

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

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

从HeidiSQL中看到的数据库布局

因此,我在这里查找了一些信息,发现多对多连接不是实体,因此不能具有值。 所以我尝试将其更改为与其他内容相关联的单独表格,但它仍然无法正常工作。

我在这里做错了什么?


好的,我发现有几个提到使用Doctrine不可能建立多对多连接的评论,并建议避免这些关系。但是,如果您真的陷入了像我在原始问题中描述的情况怎么办呢?我有一个完全依赖于多对多关系的与Magento兼容的整个数据库。所以基本上我被告知“Doctrine ORM无法处理多对多关系,请勿使用”? - Henry van Megen
3
如果可能的话我会给你+100分,因为你非常努力地解释了我想知道的内容,并以一种很好的方式表达出来,让人感觉很舒服 :-) - Torsten Römer
2个回答

153

具有额外值的多对多关联不是多对多,而是一种新实体,因为它现在具有标识符(连接实体的两个关系)和值。

这也是为什么多对多关联如此罕见的原因:您倾向于在其中存储其他属性,例如排序数量等。

您可能需要的是以下内容(我使两个关系为双向的,请考虑将它们中的至少一个单向):

产品:

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 在生成模式时,数据库并不重要 - DBAL会抛出异常,因为它在DDL元数据(内存中)中找不到列。 - Ocramius
@Ocramius 我的意思是DB是由元数据生成的。如果它能够在第一次生成列时生成它,那么它应该能够在查询期间找到它。解决我的问题的方法是将Stock.store与所需的id进行比较。 - afilina
谢谢!但是,我在哪里放置一个ArrayCollection来控制它? - Szag-Ot
@Ocramius https://pt.stackoverflow.com/questions/207760/doctrine-relacionamento-manytomany-com-campos-extras - Szag-Ot
显示剩余9条评论

17

Doctrine可以很好地处理多对多关系。

你遇到的问题是,你不需要简单的ManyToMany关联,因为关联不能有“额外”的数据。

由于中间(库存)表包含的不仅仅是product_id和store_id,所以它需要自己的实体来建模那些额外的数据。

因此,你真正想要三个实体类:

  • Product
  • StockLevel
  • Store

和两个关联:

  • Product oneToMany StockLevel
  • Store oneToMany StockLevel

1
谢谢您的答复!我已经向我的“库存”表中添加了额外的字段。然而,Doctrine 仍然不将这个“join 表格”考虑在内,并在运行 php app/console doctrine:mapping:import AppBundle yml 导入数据库架构时跳过它。 我希望它能够生成这个额外的映射 YAML 文件。 有人有什么想法吗? :( - Stphane
回答未解决将数据写入“connection”实体的问题。这是一个问题。没有声明实体。请问有人可以提供一个例子,其中数据从表单传递(CollectionType字段具有嵌入式表单和EntityType字段)。我无法从嵌入式表单传递数据到主表单,并正确保存字段集合。 - zoore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接