我有这两个数据库表:
地点
ID
命名
用户
ID
LOCATION_ID
姓氏
如first_name
我还有用户和位置类,它们都扩展了模型并包含一些自定义方法。例如,用户类中有 get_full_name()方法。
我使用以下代码加载数据
$this->db->select('users.id, locations.name as location_name, users.last_name, users.first_name');
$this->db->from('users');
$this->db->join('locations', 'users.location_id = location.id');
$query = $this->db->get();
$users= $query->custom_result_object('User'); //now $users is an array of User object
custom_result_object 是Codeigniter中内置但未记录的功能。它接受一个类名字符串,并使用它来创建该类的对象。
使用上述代码,我可以访问这样的数据,
foreach($users as $user)
{
echo $user->id;
echo $user->get_full_name();
echo $user->location_name;
}
但正如您所看到的,location_name现在是用户对象的一个字段,我想要的是用户对象的字段为位置允许我像这样使用它的对象,
foreach($users as $user)
{
echo $user->id;
echo $user->get_full_name();
echo $user->location->name; // Location is an object
}
我不想使用DataMapper ORM或任何其他ORM,也希望避免N + 1查询性能问题。
如何以最少的代码执行此操作?
注意:我为了演示目的而编写了这个例子,在我的实际情况中,有很多表和类(它们上面定义了自定义方法)。
非常感谢大家。
答案 0 :(得分:2)
您是否考虑过以下内容?
class User {
var location;
public function location()
{
if ( empty($this->location) )
{
$ci =& get_instance();
$this->location = $ci->db->get_where('locations', array('id' => $this->location_id))->row();
}
return $this->location;
}
}
这样,您可以完全避免加载位置表的开销,除非您需要数据,在这种情况下,您将其缓存在对象中以备将来使用。
答案 1 :(得分:0)
我曾对自己提出同样的质疑,但发现最简单的方法是遍历每个结果(在您的情况下,用户)并选择相应的子(位置)并设置为父对象中的字段(user->位置)。
我能想到的唯一替代方法是编辑(或扩展和创建自己的数据库集)db_result类以使用getter / setter而不是直接字段 - 可能使用call_user_func_array()。此时,您可以在用户模型中编写setId()函数,以便在收到userId / foreign键时设置$ location字段。
答案 2 :(得分:0)
从表用户获取位置ID,使用它的数字通过id对象从表位置获取。并把它放进去。