3

我最近正在阅读Doctrine 2's best practice并被此阻止:

25.3. 避免使用复合键
即使 Doctrine 完全支持复合键,如果可能的话最好不要使用它们。复合键需要 Doctrine 进行额外的工作,因此出错的可能性更高。

我不明白的是:如果"Doctrine fully supports composite keys",在处理这样的键时怎么会出错?

因此,我想以社区 wiki 的形式提出这个问题,希望它能帮助我们理解它们是什么"probability of errors"

您是否有示例可以分享您遇到的情况,即Doctrine 2没有很好地处理复合键/应有的情况?

4

2 回答 2

3

就我而言,我相信我已经遇到了一个非常基本的数据库模式的一些问题,该模式包含一个主键由 2 个外键组成的表:

在此处输入图像描述

当我生成模型时,product_i18n不会创建与实体对应的实体

$ php doctrine-module.php orm:convert-mapping --namespace="Dbi\Entity\\" \
--from-database --force annotation module/Dbi/src/
Processing entity "Dbi\Entity\Locale"
Processing entity "Dbi\Entity\Product"

$ php doctrine-module.php orm:generate-entities --generate-annotations=1 \
module/Dbi/src
Processing entity "Dbi\Entity\Locale"
Processing entity "Dbi\Entity\Product"

然而,我相信我的数据库架构是正确创建的:

  PRIMARY KEY (`product_id`, `locale_id`) ,
  INDEX `fk_product_i18n_locale` (`locale_id` ASC) ,
  INDEX `fk_product_i18n_product` (`product_id` ASC) ,
  CONSTRAINT `fk_product_i18n_locale`
    FOREIGN KEY (`locale_id` )
    REFERENCES `mydb`.`locale` (`id` ),
  CONSTRAINT `fk_product_i18n_product`
    FOREIGN KEY (`product_id` )
    REFERENCES `mydb`.`product` (`id` )

此外,Doctrine 2'Schema Manager表明 Doctrine 似乎完美地理解了这种关系(var_dump输出已更改以使其更简洁:删除诸如array, RECURSION, string... 之类的东西):

$em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
$sm = $em->getConnection()->getSchemaManager();
var_dump($sm->->listTables());

object(Doctrine\DBAL\Schema\Table)#290 (10) {
["_name":protected]=> "product_i18n"

["_indexes":protected]=>
  ["primary"]=>
    ["_columns":protected]=>
      [0]=> "product_id"
      [1]=> "locale_id"

["_fkConstraints":protected]=>
  ["fk_product_i18n_locale"]=>
  object(Doctrine\DBAL\Schema\ForeignKeyConstraint)#285 (9) {
    ["_localColumnNames":protected]=> "locale_id"
    ["_foreignTableName":protected]=> "locale"
    ["_foreignColumnNames":protected]=> "id"

  ["fk_product_i18n_product"]=>
  object(Doctrine\DBAL\Schema\ForeignKeyConstraint)#286 (9) {
    ["_localColumnNames":protected]=> "product_id"
    ["_foreignTableName":protected]=> "product"
    ["_foreignColumnNames":protected]=> "id"

因此,我处于可以查询product_i18n表的模式,但由于未生成相应的实体模型而无法与该表交互的情况。

更新:正如所user1136666指出的:已知问题和限制页面颂歌陈述如下:

尽管我们声明我们支持当前不包含外键作为主键列的复合主键。

解决方法是定义代理键并在外键上添加唯一约束,如下所示:

CREATE  TABLE IF NOT EXISTS `mydb`.`product_i18n` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `name` VARCHAR(45) NULL ,
  `description` TEXT NULL ,
  `created_at` DATETIME NULL ,
  `modified_at` DATETIME NULL ,
  `product_id` INT NOT NULL ,
  `locale_id` INT NOT NULL ,
  INDEX `fk_product_i18n_locale` (`locale_id` ASC) ,
  INDEX `fk_product_i18n_product` (`product_id` ASC) ,
  PRIMARY KEY (`id`) ,
  UNIQUE (`locale_id` , `product_id`),
  CONSTRAINT `fk_product_i18n_locale`
    FOREIGN KEY (`locale_id` )
    REFERENCES `mydb`.`locale` (`id` )
  CONSTRAINT `fk_product_i18n_product`
    FOREIGN KEY (`product_id` )
    REFERENCES `mydb`.`product` (`id` )
ENGINE = InnoDB;

功能请求: http: //www.doctrine-project.org/jira/browse/DDC-1926

于 2012-07-11T07:19:39.137 回答
2

表 product_i18n 的问题是它没有主键。请尝试将product_id和设置locale_id为复合主键。Doctrine 2 将生成实体。原则 2 实体需要主键。

于 2012-07-11T17:40:18.133 回答