在我的PHP MVC应用程序中,我有三个主要实体:组织,员工和角色。每个组织都有许多员工,每个员工都有一个角色。
对于给定的组织,我想显示一个Employees列表。对于每位员工,我将显示姓名,地址详细信息和角色名称。
现在,据我所知,最有效的方法是让我的服务层将员工列表作为数组返回,其中每个元素都是一个数据字段数组(不是对象)。在映射器中,我将角色表连接到employee表,因此正确的角色名称将位于初始结果集中,并且不需要再次查询数据库。
另一种方法是让我的服务层返回一组Employee对象。但是,在这种情况下,每个Employee对象都需要查询数据库以找到其角色的正确名称(假设角色是延迟加载的)。这将是非常低效的,但不知何故似乎更“面向对象”。
我可以考虑在实例化Employee时将角色名称作为Employee的属性加载,但是我仍然需要保留对唯一角色ID的引用,因此我立即考虑了同步。
解决这个问题的典型方法是什么?我相信它已经解决了数百万次!
谢谢!
答案 0 :(得分:1)
确实,这个东西很标准。但我仍然在努力。
我的第一个想法是建立类似的东西:
class Employee
{
protected $name; //etc
/**
* @var Organization
*/
protected $organization;
/**
* @var Role
*/
protected $role;
// And then getters/setters for Role and Organization
}
然后是一个类似于:
的EmployeeMapperclass EmployeeMapper
{
/**
* @Var DB
*/
protectd $db;
public function __construct(DB $db)
{
$this->db = $db
}
public function getEmployeesByOrganization($orgId)
{
// query here that joins employees, roles, and organizations
}
}
这让我觉得很干净,代表了你描述的结构。
但问题是当EmployeeMapper必须构造Employee对象时, 他需要知道联接的查询结果中的角色字段和组织字段如何映射到角色和组织对象中的字段。对我而言,该知识应严格存在于RoleMapper和OrganizationMapper中。因此,这些映射器可能需要将此映射功能作为公共方法提供,我们需要有一种方法将RoleMapper和OrganizationMapper实例注入到EmployeeMapper中以供使用。有关基于ZF的示例,请参阅Surviving The Deep End。
此外,有时似乎 - 就像您提供的“员工视图列表”示例一样 - 您希望获得有关这些附加的角色和组织实体的信息。在这种情况下,加入和构建对象图的开销是合理的(当然比为角色和组织进行单独的循环查询更好)。但在其他情况下,您实际上只希望为一个员工提供一些简单的员工信息,例如他的姓名或号码。在后一种情况下,为什么会产生加入和构建完整对象图的开销?
这些问题有一些架构解决方案,通常使用代理对象(代表角色和组织对象,并在需要时延迟加载它们)和自定义存储库对象(您要强制连接的位置)。
但我发现自己设计所有这些都是一种痛苦。最后,我发现像Doctrine这样的ORM已经完全解决了这个问题并为我提供了上述功能(代理,自定义存储库等)。