处理与Data Mapper模式的关系

时间:2012-12-05 13:58:52

标签: php design-patterns orm datamapper

我正在使用Data Mapper模式,我想知道处理该模式关系的最佳方法是什么。我花了很多时间在谷歌搜索解决方案和堆栈溢出,我发现了一些,但我仍然不是很满意他们,特别是在我将尝试解释的一个特殊案例中。

我正在使用PHP,所以我将放在PHP中的代码示例。

假设我有一个表“团队”(id,name)和一个表“player”(id,name,team_id)。这是一个1-N的关系。 通过实现Data Mapper模式,我们将拥有以下类:Team,TeamMapper,Player和PlayerMapper。

到目前为止,一切都很简单。如果我们想要从团队中获得所有玩家怎么办?

我找到的第一个解决方案是在Team类中创建一个方法getAllPlayers(),它将使用延迟加载和代理来处理它。然后,我们可以检索这样一个团队的球员:

$players = $team->getAllPlayers();

我找到的第二个解决方案是直接使用PlayerMapper并将团队ID作为参数传递。类似的东西:

$playerMapper->findAll(array('team_id' => $team->getId()));

但是现在,让我们说我希望显示一个包含所有团队的HTML表格,以及每个团队所有玩家的“玩家”栏目。如果我们使用我描述的第一个解决方案,我们将不得不做一个SQL查询来获取团队列表和每个团队的一个查询来获取玩家,这意味着N + 1个SQL查询,其中N是团队数量。 / p>

如果我们使用我描述的第二个解决方案,我们可以先检索所有团队ID,将它们放入数组中,然后将其传递给播放器映射器的findAll方法,如下所示:

$playerMapper->findAll(array('team_id' => $teamIds));

在这种情况下,我们只需要运行2个查询。好多了。但我对这个解决方案仍然不满意,因为关系没有被描述到模型中,开发人员必须了解它们。

所以我的问题是:Data Mapper模式还有其他替代方案吗?通过我给出的示例,是否有一种很好的方法可以在2个查询中选择所有参与者的所有团队,并描述模型中的关系?

提前谢谢!

2 个答案:

答案 0 :(得分:2)

如果你看一下描述DataMapper如何工作的Martin Fowler的文本,你会看到你可以使用一个查询来获取你需要的所有数据,然后将这些数据传递给每个mapper,从而允许mapper选择只有它需要的数据。

对于您来说,这将是一个从Team加入Player的查询,返回一个结果集,其中包含每个唯一Player的重复Team数据。

然后,您必须通过仅在数据更改时创建新对象来满足映射代码中的重复。

我做过类似的事情,相当于团队映射器迭代结果集,并且每个唯一团队将结果集传递给Player映射器,以便它可以创建一个播放器,然后将播放器添加到团队的收藏。

虽然这会起作用,但这种方法在下游还有问题......

答案 1 :(得分:0)

我已经在我的一个项目中成功实现了这个问题的可能解决方案。它不是那么复杂,在上述示例中仅使用2个查询。

解决方案是添加另一层负责处理关系的代码。

例如,我们可以将它放在一个服务类中(也可以用于其他东西,而不仅仅是处理关系)。 因此,我们假设我们在Team和TeamMapper之上有一个TeamService类。 TeamService将有一个方法getTeamsWithRelationships(),它将返回Team对象的数组。 getTeamsWithRelationships()将使用TeamMapper获取团队列表。然后,使用PlayerMapper,它只会在一个查询中获得这些团队的玩家列表,并使用Team类中的setPlayers()方法将玩家设置为团队。

此解决方案非常简单且易于实现,并且适用于所有类型的数据库关系。我想有些人可能会反对它。如果是这样,我很想知道有什么问题?