2

次の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`);

2 つの skill_category 列間の外部キーの関係に注意してください。

テーブル構造

これらのテーブル間に多対一/一対多の関係を作成しようとしています。1 つの固有の skill_category には、多くのスキルが必要です。この構造は正常に動作しているように見えますが、マッピングを検証しようとするとエラーが発生します。

参照される列名 'skill_category' は、ターゲット エンティティ クラス 'Resume\ResumeBundle\Entity\SkillsCategories' の主キー列である必要があります。

参照される列が主キーであるという原則による要件があります。このキーを主キーにすると、id 列が自動的にインクリメントされなくなります。したがって、mySQL は外部キーが主キーであるという事実に問題ないように見えますが、Doctrine はこのケースについて不平を言っています。列を再作成するだけで修正したと誰かが言った:

http://goo.gl/vvq0tu

私はこれを試しましたが、私には役に立たなかったようです。したがって、これはある種のバグであるか、RDBMS の基本的な誤解があります (完全に可能性があります)。「id」列をまったく使用すべきではないという私の問題ですか? 「skills_category」列が一意であると予想される場合、それを主キーにして「id」列を削除する必要がありますか? これで問題は解決しますが、VARCHAR を主キーにすることに問題はありますか? Googleの答えは「そうではない」ようですが、他の誰かからの視点をいただければ幸いです.

4

2 に答える 2

2

これは、私が Doctrine を使い始めたときとまったく同じ問題でした。そうです、Doctrine がオブジェクトをリレーショナル データベースにマップする方法についてのわずかな誤解が原因です。

「リレーショナル」な世界から一歩踏み出し、エンティティをオブジェクトのように扱うことから始めましょう。あなたの場合、ここには 2 つのクラスのオブジェクトがあります。スキルがあり、カテゴリがあります。

プレイ中のオブジェクトはこれら 2 つだけです。SkillsCategories エンティティのようなものはありません... オブジェクトとしては意味がありません。これは関係です。そのため、ID を付与してもあまり意味がありません。

では、これら 2 つのエンティティは実際にはどのように見えるのでしょうか?

スキル:

  • ID
  • 名前
  • アイコンのファイル名
  • 表示優先度
  • 属するカテゴリ エンティティ

カテゴリー:

  • ID
  • 名前
  • それに属する Skill エンティティのリスト

そして、これらのエンティティをデータベースに入れると、期待どおりに見えます (カテゴリに属する​​スキルのリストをマップしていないことを除いては、これは後で 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

これで、完全に機能するモデルが完成しました。

いくつかの例...

Skill の 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 に答える