更改 Doctrine2 的 ManyToMany 关系中介的字符集和引擎 table

Change charset and engine for Doctrine2's ManyToMany relationship's intermediary table

我正在 Symfony2 中的两个实体之间建立这种 ManyToMany 关系,并希望链接 table 成为 charset latin1engine MyISAM(默认为UTF-8和InnoDB)。

他们在这里:

Entity\Commande

<?php
// ...
/**
 * Commande
 *
 * @ORM\Table(name="commande", options={"collate"="latin1_general_ci", "charset"="latin1", "engine":"MyISAM"})
 * @ORM\Entity()
 */
class Commande
{
    // ...

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Paiement", inversedBy="commandes", cascade={"persist"})
     * @ORM\JoinTable(name="paiement_commande",
     * joinColumns={@ORM\JoinColumn(name="commande_id", referencedColumnName="id")},
     * inverseJoinColumns={@ORM\JoinColumn(name="paiement_id", referencedColumnName="id")}
     * )
     */
    private $paiements;

Entity\Paiement

<?php
// ...
/**
 * Paiement
 *
 * @ORM\Table(name="paiement", options={"collate"="latin1_general_ci", "charset"="latin1", "engine":"MyISAM"})
 * @ORM\Entity()
 */
class Paiement
{
    // ...

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Commande", mappedBy="paiements", cascade={"persist"})
     * @ORM\JoinTable(name="paiement_commande")
     */
    private $commandes;

如您所见,我知道如何为我的实体 table 正确设置此信息,但我如何为 paiement_commande table 设置此信息?


我试过:

/*
 * @ORM\JoinTable(name="paiement_commande", options={"collate"="latin1_general_ci", "charset"="latin1", "engine":"MyISAM"})
 */
private $commandes;

但我从 $ php app/console doctrine:schema:validate 命令中得到:

 [Doctrine\Common\Annotations\AnnotationException]                                                                                                                                         
 [Creation Error] The annotation @ORM\JoinTable declared on property Entity\Paiement::$commandes does not have a property named "options". Available properties: name, schema, joinColumns, inverseJoinColumns   

如何在我的两个实体之间设置这种 ManyToMany 关系并且仍然能够为新创建的链接 table 指定 enginecharset

感谢您的帮助!

不幸的是,您无法通过学说来控制 join-tables 的引擎、字符集、排序规则和其他属性。如您所见,@JoinTable 注释没有 options 参数,而 @Table 有。

但是您始终可以手动管理这些事情,并且 Doctrine 不会抱怨(在验证架构时)。因此,要么自己创建 join-table,要么让 Doctrine 创建它并根据您的意愿进行调整。

个人建议

恕我直言,您不应该依赖 Doctrine 来创建或更改您的模式。

使用 Doctrine 的控制台命令来创建和更改数据库对于您的开发数据库来说很好,并且对于获得 SQL 您需要什么的初步指示也很有用(参见 orm:schema-tool:update --dump-sql)。

但对于生产用途,此 SQL 应 始终 手动修改。教义并不总能产生正确的 SQL。就像您遇到的情况一样,还有其他未考虑的边缘情况。

其他工具

我建议您看看其他一些管理数据库迁移的工具。

Doctrine Migrations 是一个。请注意,此工具依赖于 Doctrine ORM 来生成 SQL(请参阅 migrations:diff),因此您将 运行 遇到相同的问题。不同之处在于,您可以让它创建 "versions",然后您可以对其进行修改和更改,直到获得您想要的内容。最后的 "version" 是您应用于数据库的内容。

另一种流行的迁移工具是 Phinx。它更加动态且独立于框架(因此它不需要 Doctrine)。

Doctrine 在任何关系映射上使用 foreign_keys - 这些仅在 InnoDB 中可用。 除此之外,当您尝试在非事务引擎(如 MyISAM)上执行事务时,学说将失败,here。 毕竟 Doctrine 2.2 或 2.3

中有一些 implementations

我的建议是让 Doctrine 和 InnoDB 做他们擅长的事情,处理引用完整性和关系。可能您想将 MyISAM 用于搜索功能,因此最好为此创建相关数据的副本。

您可以挂钩 Doctrine 触发的所有事件,并将实体数据复制到另一个 table。这些事件真的很强大,可以让你连接到几乎所有场景:http://doctrine-orm.readthedocs.org/en/latest/reference/events.html

您可以在 Symfony 中创建一个订阅者,专注于处理该实体的所有事件:http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html

一个技巧可能是使用另一个实体作为连接 table。

简单地说:

<?php
// ...
/**
 * PaiementCommande
 *
 * @ORM\Table(name="paiement_commande", options={"collate"="latin1_general_ci", "charset"="latin1", "engine":"MyISAM"})
 * @ORM\Entity()
 */
class PaiementCommande
{
    // ...

    /**         *
     * @ORM\ManyToOne(targetEntity="Commande")
     */
    private $commande;

    /**         *
     * @ORM\ManyToOne(targetEntity="Paiement")
     */
    private $paiement;

我认为无论如何使用这种中间实体会更好,因为在您的应用程序中的某一时刻您可能需要存储中间数据,而这是执行此操作的唯一方法(并更改每一段代码关系会很痛苦)。