2

我有以下两个表:

CREATE TABLE IF NOT EXISTS `skills` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `skill_category` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `skill` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `icon_filename` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `display_priority` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `skill_category` (`skill_category`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `skills_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `skill_category` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `display_priority` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_95FF1C8D47E90E27` (`skill_category`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

ALTER TABLE `skills`
  ADD CONSTRAINT `skills_ibfk_1` FOREIGN KEY (`skill_category`) REFERENCES `skills_categories` (`skill_category`);

注意两个 Skill_category 列之间的外键关系。

表结构

我正在尝试在这些表之间创建多对一/单对多关系。一个独特的技能类别应该有很多技能。这种结构似乎工作正常,除非我尝试验证映射时出现错误:

引用的列名“skill_category”必须是目标实体类“Resume\ResumeBundle\Entity\SkillsCategories”上的主键列。

学说要求被引用的列是主键。如果我将此键设为主键,我的 id 列将不再自动递增,这是我想要的。所以 mySQL 似乎可以接受外键是主键的事实,但是 Doctrine 抱怨这种情况。有人说他们只是通过重新创建列来修复它:

http://goo.gl/vvq0tu

我试过这个,它似乎对我没有帮助。所以要么这是某种错误,要么我对 RDBMS 有根本的误解(完全可能)。我的问题是我根本不应该使用“id”列吗?如果我希望我的 'skills_category' 列是唯一的,我应该将其作为主键并删除 'id' 列?那将解决我的问题,但是将 VARCHAR 作为主键有什么问题吗?谷歌的答案似乎是“不是真的”,但我希望能从其他人那里获得一些观点。

4

2 回答 2

2

这与我第一次开始使用 Doctrine 时遇到的问题完全相同,是的,它来自对 Doctrine 如何将对象映射到关系数据库的轻微误解。

让我们从走出“关系”世界开始,将您的实体视为对象。在你的情况下,这里有两类对象:你有一个技能,你有一个类别。

这些是唯一起作用的两个对象。没有 SkillsCategories 实体之类的东西……它作为一个对象没有意义——它是一种关系。因此,给它一个 ID 并没有多大意义。

那么这两个实体实际上是什么样的呢?

技能:

  • 身份证
  • 一个名字
  • 图标文件名
  • 显示优先级
  • 所属的 Category 实体

类别:

  • 身份证
  • 一个名字
  • 属于它的技能实体列表

当您将这些实体放入数据库时​​,它看起来就像您期望的那样(除了我们没有映射属于某个类别的技能列表——这将由 Doctrine 稍后处理)。我建议您更新架构以反映此更改:

CREATE TABLE IF NOT EXISTS `Skill` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `categoryId` int(11) NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `iconFilename` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `displayPriority` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `skill_category` (`categoryId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `Category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `displayPriority` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_95FF1C8D47E90E27` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

现在您可以通过 Doctrine 定义关系。以下是使用 YAML 时的样子:

Path\To\Entity\Skill:
    type: entity
    table: Skill
    fields:
        id:
            id: true
            type: integer
            generator
                strategy: AUTO
        name:
            type: string
            length: 255
        iconFilename:
            type: string
            length: 50
        displayPriority:
            type: integer
    manyToOne:
        category:
            targetEntity: Category
            inversedBy: skills
            joinColumn:
                name: categoryId
                referencedColumnName: id

Path\To\Entity\Category:
    type: entity
    table: Category
    fields:
        id:
            id: true
            type: integer
            generator
                strategy: AUTO
        name:
            type: string
            length: 255
        displayPriority:
            type: integer
    oneToMany:
        skills:
            targetEntity: Skill
            mappedBy: category

现在你有了一个完全可用的模型!

一些例子...

假设您想获得技能类别的 displayPriority:

$skill->getCategory()->getDisplayPriority();

...或者如果您想获取给定类别下的技能名称列表:

foreach ($category->getSkills() as $skill) {
    echo $skill->getName();
}

希望这有助于澄清一些事情......

于 2013-08-07T01:06:48.923 回答
0

将 varchar 作为主键没有问题。如果您确实有空间或密钥大小的要求,您可以设置一个查找代码表,但这会使您的数据库和代码比需要的更复杂。

我个人仅将自动增量键用于来自我无法控制的流程的输入:订单、票证、事件等。通常,您正在从 Web 流程中跟踪这些内容。

于 2013-08-07T00:40:49.820 回答