更改 Doctrine2 的 ManyToMany 关系中介的字符集和引擎 table
Change charset and engine for Doctrine2's ManyToMany relationship's intermediary table
我正在 Symfony2 中的两个实体之间建立这种 ManyToMany 关系,并希望链接 table 成为 charset
latin1 和 engine
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 指定 engine
和 charset
?
感谢您的帮助!
不幸的是,您无法通过学说来控制 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;
我认为无论如何使用这种中间实体会更好,因为在您的应用程序中的某一时刻您可能需要存储中间数据,而这是执行此操作的唯一方法(并更改每一段代码关系会很痛苦)。
我正在 Symfony2 中的两个实体之间建立这种 ManyToMany 关系,并希望链接 table 成为 charset
latin1 和 engine
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 指定 engine
和 charset
?
感谢您的帮助!
不幸的是,您无法通过学说来控制 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
我的建议是让 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;
我认为无论如何使用这种中间实体会更好,因为在您的应用程序中的某一时刻您可能需要存储中间数据,而这是执行此操作的唯一方法(并更改每一段代码关系会很痛苦)。