教义2和多对多链接表,带有一个额外的字段


88

(很抱歉,我的问题不连贯:撰写本文时,我试图回答一些问题,但这是:)

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

基本的多商店,多产品商店保存系统的数据库模型

对于这个简单的示例,我已经使用exportmwb生成了两个实体商店和产品,两者均显示在下面。

但是,现在的问题是,我无法弄清楚如何使用Doctrine访问stock.amount值(带符号int,因为它可以是负数)。另外,当我尝试使用主义的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中看到的数据库布局

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

我在这里做错了什么?


好的,我发现有两点提及,指出使用Doctrine不可能建立多对多的连接,并提出建议以防止这些关系。但是,如果您真的陷入这种情况,该怎么办?我最初的问题?我有一个与Magento兼容的完整数据库,它完全依赖于多对多关系。所以基本上我被告知“ Doctrine ORM无法处理多对多,不要使用它”?
亨利·范·梅根


3
如果可以的话,我会给您+100,以便您以一种很好的方式来确切地解释我想知道的事情:-)
TorstenRömer2014年

Answers:


141

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

这也是为什么许多-to-many关联是如此罕见:你会存储在他们的附加属性,如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方法,因为使用此设置,我只会启动并运行没有任何值的主键:)
Henry van Megen 2013年

当我使用此设置,然后尝试使用Stock.store_id进行查询时,出现错误“股票没有名为store_id的字段或关联”。应该找到它,因为该列存在于数据库中。
阿菲莉娜(Afilina)2013年

@afilina db在生成模式时无关紧要-DBAL引发异常,因为它未在DDL元数据中(在内存中)找到该列
Ocramius

@Ocramius我的意思是数据库是从元数据生成的。如果首先能够生成该列,则它应该能够在查询期间找到它。我的问题的解决方案是将Stock.store与所需的ID进行比较。
2013年

100%我需要的东西,就像魅力一样!您是否知道如何使用字段集构建表单以编辑每个商店和产品的金额?
cwhisperer 2014年

17

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

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

您的中间(库存)表由于包含的不仅仅是product_id和store_id,因此需要使用自己的实体来建模该额外数据。

因此,您确实需要三类实体:

  • 产品
  • 库存水平
  • 商店

和两个关联:

  • 产品oneToMany库存水平
  • 存储一对多库存水平

1
谢谢您的回答 !我在表格的“股票”中添加了额外的字段。但是,当我运行php app/console doctrine:mapping:import AppBundle yml以便从数据库导入架构时,学说仍然不考虑该“联接表”,并跳过它。我希望它生成此额外的映射yaml文件。有人有什么主意吗 ?:(
斯特凡2015年

回答不解决将数据写入“连接”实体的问题。这是个问题。没有声明实体。可以请有人支持从Form传递数据的示例(CollectionType字段已嵌入带有EntityType字段的表单)。我无法将数据从嵌入表单传递到主表单,也无法正确保存字段集合
zoore
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.