Mysql 1-N与不是主键的外键的关系(主键是doctrine2/symfony2的自动增量';id';)

Mysql 1-N与不是主键的外键的关系(主键是doctrine2/symfony2的自动增量';id';),mysql,symfony,doctrine-orm,doctrine,rdbms,Mysql,Symfony,Doctrine Orm,Doctrine,Rdbms,我有以下两个表格: 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,

我有以下两个表格:

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列之间的外键关系

我试图在这些表之间创建一个manytone/onetomany关系。一个独特的技能类别应该有很多技能。此结构似乎工作正常,但当我尝试验证映射时,我发现错误:

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

条令要求引用的列是主键。如果我将此键设为主键,则我的id列不再自动递增,这是我想要的。因此,mySQL似乎可以接受外键是主键这一事实,但Doctrine对此表示不满。有人说他们只是通过重新创建列来修复它:


我试过这个,但似乎对我没有帮助。所以要么这是某种bug,要么我对RDBMS有一个基本的误解(完全可能)。我的问题是我根本不应该使用“id”列吗?如果我希望我的“技能类别”列是唯一的,那么我应该将其作为主键并删除“id”列?这可以解决我的问题,但是将VARCHAR作为主键有什么问题吗?谷歌的答案似乎是“不是真的”,但我希望能从其他人的角度来看问题。

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

我个人只对我不控制的流程的输入使用自动递增键:订单、票据、事件等。通常情况下,您要从web流程跟踪的内容。

这与我第一次开始使用条令时遇到的问题完全相同,是的,它源于对条令如何将对象映射到关系数据库的一点误解

让我们从走出“关系”世界开始,像对待对象一样对待实体。在您的例子中,这里有两类对象:一类是技能,另一类是类别

这是仅有的两个发挥作用的对象。世上没有所谓的技能等级实体。。。它作为一个对象没有意义——它是一种关系。因此,给它一个ID并没有多大意义

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

技能:

  • 身份证
  • 名字
  • 图标文件名
  • 显示优先级
  • 它所属的类别实体
类别:

$skill->getCategory()->getDisplayPriority();
foreach ($category->getSkills() as $skill) {
    echo $skill->getName();
}
  • 身份证
  • 名字
  • 属于它的技能实体的列表
当你把这些实体放到数据库中时,它看起来就像你期望的那样(除了我们没有映射属于某个类别的技能列表——这将在后面由条令来处理)。我建议您更新架构以反映此更改:

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 ;
现在你可以通过条令来定义这种关系。以下是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
现在你有了一个完全工作的模型

一些例子

假设您想要获得技能类别的显示优先级:

$skill->getCategory()->getDisplayPriority();
foreach ($category->getSkills() as $skill) {
    echo $skill->getName();
}
…或者如果您想获得给定类别下的技能名称列表:

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

希望这有助于澄清一些问题…

感谢您的帮助,我实现了您的解决方案,但后来意识到您正在将“skillId”加入现有的“id”主键。我可以这样做,但为了便于数据插入(我使用phpmyadmin插入,我不想查找我想要使用的每个类别的对应id;我宁愿直接使用类别,而不必乱用id。如果我这样做(通过类别而不是id连接表),那么我需要类别作为主键(条令要求),如果我这样做,那么如果ID不是主键,那么ID不会增加(mysql要求?)哇,是的…我的意思是
技能
->
类别
加入列名为
categoryId
,而不是
skillId
。很抱歉!至于手动数据库更新,你能在phpMyAdmin中这样做吗:
插入技能(名称、iconFilename、displayPriority、categoryId)选择“某个技能名称”,“图标文件”,5,类别id,其中name=“某些类别名称"
?这将使用您的
选择的结果作为插入
的基础。我只是不确定为了使数据输入更容易而削弱您的模型是否是一个好主意。再次感谢您的帮助。我宁愿更改模型,并使用phpmyadmin ui插入数据。我就不能全部删除ID吗同时。什么需要在类别表上有一个id?我已经创建了唯一的类别名称,这些不能是我的主键吗?然后列的数量减少2,我可以用我想要的方式使用phpadmin,条令不会给我上面的错误抱歉,我想你的要求之一是拥有一个自动递增的类别id?是的h、 我在想,如果我与一位真正的RDBMS专家交谈,他们会说‘如果你创建的是唯一的类别,为什么要使用自动增量id?当类别提供这种唯一性时,没有必要使用唯一id’。但是,我再次了解了有关代理v.s自然键的更多信息,一些人主张总是使用代理键: