【问题标题】:Entity having two entities of the same type具有两个相同类型实体的实体
【发布时间】:2013-03-03 12:51:33
【问题描述】:

我正在编写一个小游戏,需要一个代表玩家和比赛的数据库。

一个玩家有一个名字、一个玩家ID和一个等级。 一场比赛有一个 ID 和两个玩家。

播放器

  • id (bigint)
  • 名称(字符串)
  • 玩家ID(字符串)
  • 排名(整数)

匹配

  • id (bigint)
  • 匹配ID(字符串)
  • playerOne(玩家)
  • playerTwo(玩家)

最终,我想在 Player 中建立“匹配”关系,但我不明白的一点是如何让一个实体具有两个相同类型的实体,我应该使用什么类型的关系?

我尝试过使用一对一关系,但它创建的唯一条件是个问题。

欢迎提出任何想法。

干杯。

西里尔

【问题讨论】:

  • 找出关系的一个好方法是大声说话。在您的情况下,您应该说“一个玩家可以玩多场比赛”和“一场比赛可以有多个玩家”,翻译成ManyToMany。如果是OneToOne,你会说“一个玩家只能玩一场比赛”和“一场比赛只能包括一名球员”(除非你将多个OneToOne添加到Player,但这并不灵活)。跨度>

标签: symfony doctrine entity-relationship database-schema


【解决方案1】:

您需要多对多的关系。这通常使用“中间”或“链接”表来完成。在此示例中,PlayedMatch 表是链接表。

这实际上是 Player 和 Match 之间的单个多对多关系。但是,它由 2 个一对多关系表示:

玩家 [1] --> [n] PlayedMatch

比赛 [1] --> [n] PlayedMatch

Player
  Id
  Name
  Rank

Match
  Id

PlayedMatch
  Id
  MatchId
  Player1Id
  Player2Id

我看到您有一些名为 PlayerId 和 MatchId 的字符串属性。尽量避免使用这些名称,因为它们通常用于外键关系。

您可能希望PlayedMatch 表中有更多属性,例如WinnerId(链接到播放器)。

上面的 SQL 查询看起来像这样:

SELECT 
  *
FROM
  PlayedMatch pm
    INNER JOIN Player p1 ON pm.Player1Id = p1.Id
    INNER JOIN Player p2 ON pm.Player2Id = p2.Id
    INNER JOIN Match m ON pm.MatchId = m.Id

【讨论】:

  • 有趣,那么这三个实体之间的关系是什么。 Player 和 PlayedMatch 之间可能是多对多关系,Match 和 PlayerMatch 之间可能是一对多关系?关于如何在 Symfony 中执行此操作的任何提示?
  • 实际上这只是 Player 和 Match 之间的 1 多对多关系。从技术上讲,它由 2 个一对多关系表示。我会用更多细节更新我的答案。
  • 你是对的。但这里真正的问题是如何在玩家实体(不是原始 sql)上维护“匹配”关系,这意味着如何获取玩家的所有匹配项,无论他是 player1 还是 player2。使用这种模式,我认为 Doctrine/Symfony 没有很好的解决方案。当然,您可以有 2 个关系,matchesAsPlayer1 和 matchesAsPlayer2,以及将两者合并的另一种方法。
【解决方案2】:

如果您想轻松找到每个玩家的所有比赛,您需要使用ManyToMany 关系。以下是类的简化 sn-p。

class Player {

    /**
     * @ORM\ManyToMany(targetEntity="Match", mappedBy="players")
     */
    protected $matches;

}

class Match {

    /**
     * @ORM\ManyToMany(targetEntity="Player", inversedBy="matches")
     */
    protected $players;

}

然后从根目录运行以下命令:

php app/console doctrine:generate:entities Your/AwesomeBundle/Entity

您将能够使用以下方法:

Match::getPlayers()
Match::addPlayer()
Player::addMatch() // probably will have an 'e' at the end of the word match
Player::getMatches() // which is the one that will give you all matches of a user

您需要在代码中限制每场比赛的玩家人数。

【讨论】:

  • 这是正确的答案。如果您需要存储一些附加信息(例如获胜者、玩家顺序),您可以将它们存储在链接表中,并按照 PeteGO 的建议使用 2 个多对一关系(不是真正的多对多)。总之,拥有单一玩家关系(而不是玩家 1 和玩家 2)肯定是要走的路。
  • 这个答案有助于理解这个过程,但是请不要使用 PHP 静态方法语法,这真的很令人不安。
  • 对不起 Cyril,我理解你的观点,我只使用这种语法是因为它用于 PHP 官方文档,否则我完全同意它可能会产生误导。
猜你喜欢
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 2011-07-18
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多