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

Posted

技术标签:

【中文标题】Doctrine 2 和带有额外字段的多对多链接表【英文标题】:Doctrine 2 and Many-to-many link table with an extra field 【发布时间】:2013-03-15 00:20:09 【问题描述】:

(对不起,我的问题不连贯:我在写这篇文章时试图回答一些问题,但在这里:)

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

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

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

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

因此,从逻辑上讲,我尝试将我的数据库模型更改为将库存作为一个单独的表,其中包含与商店和产品的关系。我还重写了字段名,以便能够将其排除为问题的根源:

然后我发现我仍然没有得到 Stock 实体...而且数据库本身没有“金额”字段。

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

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

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

所以,在这里查找一些东西,我发现多对多连接不是实体,因此不能有值。所以我尝试将其更改为与其他表有关系的单独表,但它仍然不起作用。

我在这里做错了什么?

【问题讨论】:

好的,我发现有几处提到使用 Doctrine 建立多对多连接是不可能的,cmets 建议阻止这些关系.. 但是如果你真的被例如我在原始问题中描述的情况?我有一个与 Magento 兼容的完整数据库,它完全依赖于多对多关系。所以基本上我被告知“Doctrine ORM 不能处理多对多,不要使用它”?? 另见Doctrine2: Best way to handle many-to-many with extra columns in reference table 如果我可以的话,我会给你+100,因为你付出了努力,以一种很好的方式准确地解释了我想知道的事情:-) 【参考方案1】:

带有附加值的多对多关联不是多对多,而是确实是一个新实体,因为它现在有一个标识符(与连接实体的两个关系)和值。

这也是多对多关联如此罕见的原因:您倾向于在其中存储其他属性,例如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;

【讨论】:

好的,我将添加一些 getter 和 setter,因为通过此设置,我只能启动并运行没有任何值的主键 :) 当我使用此设置并尝试使用 Stock.store_id 进行查询时,我收到错误消息“Stock 没有名为 store_id 的字段或关联”。应该可以找到,因为该列存在于数据库中。 @afilina db 在生成模式时无关紧要 - DBAL 抛出异常,因为它在 DDL 元数据(内存中)中找不到列 @Ocramius 我的意思是数据库是从元数据生成的。 S如果它能够首先生成该列,那么它应该能够在查询期间找到它。我的问题的解决方案是将 Stock.store 与所需的 id 进行比较。 100% 我需要的东西,它就像一个魅力!您知道如何使用字段集构建表单以编辑每个商店和产品的金额吗?【参考方案2】:

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

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

您的中间(库存)表,因为它包含的不仅仅是 product_id 和 store_id,因此需要它自己的实体来为这些额外数据建模。

所以你真的想要三类实体:

产品 库存水平 商店

还有两个关联:

产品 oneToMany StockLevel 存储 oneToMany StockLevel

【讨论】:

感谢您的回答!我在我的“股票”中添加了额外的字段,比如表格。但是,当我运行 php app/console doctrine:mapping:import AppBundle yml 以便从数据库导入模式时,学说仍然不考虑这个“连接表”并跳过它。我希望它生成这个额外的映射 yaml 文件。有人有什么主意吗 ? :( 回答不解决将数据写入“连接”实体。这是个问题。不声明实体。可以请某人支持从表单传递数据的示例(CollectionType 字段嵌入了带有 EntityType 字段的表单)。我无法将数据从嵌入表单传递到主表单,也无法正确保存字段集合

以上是关于Doctrine 2 和带有额外字段的多对多链接表的主要内容,如果未能解决你的问题,请参考以下文章

JPA 2:通过不在带有额外字段的多对多中工作来订购

带有额外列的多对多自引用原则

如何避免与 Doctrine2 和 Zend Framework 2 的多对多关系重复?

openjpa:多对多,带有额外的列

Android Room - 带有附加字段的多对多关系

如何使用带有额外列的多对多映射保存对象?