10

I am using the Data Mapper Pattern and I am wondering what is the best way to handle relationships with that pattern. I spent a lot of time searching for solutions in Google and Stack overflow, I found some but I am still not completely happy about them, especially in one special case that I will try to explain.

I am working with PHP so the examples of code that I will put are in PHP.

Let's say I have a table "team" (id, name) and a table "player" (id, name, team_id). This is a 1-N relationship. By implementing the Data Mapper pattern, we will have the following classes: Team, TeamMapper, Player and PlayerMapper.

So far, everything is simple. What if we want to get all players from a team?

The first solution I found is to create a method getAllPlayers() in the Team class which will handle that with lazy loading and proxies. Then, we can retrieve the players of a team like that:

$players = $team->getAllPlayers();

The second solution I found is to directly use the PlayerMapper and pass the team ID as parameter. Something like:

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

But now, let's say that I want to display a HTML table with all the teams and with a column 'Players' with all of the players of each team. If we use the first solution I described, we will have to do one SQL query to get the list of teams and one query for each team to get the players, whcih means N+1 SQL queries where N is the number of teams.

If we use the second solutions I described, we can first retrieve all team IDs, put them in an array, and then pass it to the findAll method of the player mapper, something like that:

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

In that case, we need to run only 2 queries. Much better. But I am still not very happy with that solution because the relationships are not described into the models and it is the developer who must know about them.

So my question is: are there others alternatives with the Data Mapper pattern? With the example I gave, is there a good way to select all teams with all players in just 2 queries with the description of the relationships into the model?

Thank you in advance!

4

2 回答 2

2

如果您查看 Martin Fowler 描述 DataMapper 工作原理的文本,您会发现您可以使用一个查询来获取您需要的所有数据,然后将这些数据传递给每个映射器,从而允许映射器仅挑选数据它需要。

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

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

我做了类似的事情,其中​​等效的是团队映射器迭代结果集,并且对于每个独特的团队,将结果集传递给玩家映射器,以便它可以创建一个玩家,然后将玩家添加到团队的集合中。

虽然这可行,但这种方法在下游存在问题......

于 2012-12-05T16:43:28.003 回答
0

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

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

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

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

于 2015-08-12T09:45:52.610 回答