DataMapper ORM - 如何获取所有模型和每个实例的相关数据
Posted
技术标签:
【中文标题】DataMapper ORM - 如何获取所有模型和每个实例的相关数据【英文标题】:DataMapper ORM - How to get all of a model and each instance's related data 【发布时间】:2013-04-20 20:50:37 【问题描述】:我不明白如何执行以下操作:
假设我有一个产品表和一个照片表。 1 产品有很多照片。所以在产品模型中我这样做:
var $has_many = array("category", "photo");
现在我想获取所有产品并将他们的每张照片与它们相关联。我怎样才能做到这一点?目前,在我的控制器中,我正在浏览每个产品并查询照片并以这种方式传递一个单独的数组。这不可能是理想的。我应该可以将每张照片直接与特定产品联系起来,不是吗?
从逻辑上讲,这会起作用(但它不起作用?)
$product = new Product;
$products = $product->get_by_related_category('name', $where);
$photos = $product->photo->get();
看看我在说什么? 我很想将 $products 变量传递给我的视图,能够通过它进行遍历,并让一组照片与每个产品对象相关联。
我怎样才能做到这一点?或者有更好的方法吗?
谢谢!
【问题讨论】:
【参考方案1】:对于“有很多”关系,您基本上有两种使用 SQL 获取相关信息的方法:
您可以像select products.*, photos.* from products left outer join photos on products.id = photos.product_id
一样加入另一个表。这样,您将拥有“重复”的产品数据,因此您需要相应地处理结果。不幸的是include_related()
不直接支持这一点,它会创建重复的产品,每个产品都有一张相关的照片。
您可以运行两个查询,首先获取产品 (select * from products where ...
),然后获取带有所选产品 id 的照片 (select * from photos where product_id in (...)
),然后整理出哪些照片行应该放在哪些产品上。在 DMZ 中没有内置功能,但这是我为模型基类(扩展 DataMapper
类)编写的代码,可以像这样使用:
$products = new Product;
$products = $products
->get_by_related_category('name', $where) // first get the parent objects
->load_related('photo'); // then load in the related ones inside them
foreach ($products as $product)
// unique product instances as before
foreach ($product->photo as $photo)
// and every product has a list of related photos
// for each product individualy
下面的方法将收集父对象的 id,使用where_in()
中的 id 运行一个 SQL 查询,并为父对象的相关字段对象排序结果(不幸的是它有点长并且不支持多对多关系)。
/**
* load_related
*
* Loads related has_many objects efficiently
*
* @param string $related_field_name the name of the relation
* @param callable $filter_function callback to place extra conditions on the related model query
*/
public function load_related($related_field_name, $filter_function = null)
$related_properties = $this->_get_related_properties($related_field_name);
$related_models = new $related_properties['class'];
$join_field = $related_properties['join_self_as'].'_id';
$ids = array_unique(array_filter(array_merge(array('id' => $this->id), array_column($this->all, 'id')), 'intval'));
if (empty($ids))
return $this;
$related_models->where_in($join_field, $ids);
if (is_callable($filter_function))
call_user_func($filter_function, $related_models);
$related_models = $related_models->get();
$related_models = array_group_by($related_models, $join_field);
foreach ($this->all as $i => $row)
$related_models_to_row = isset($related_models[$row->id]) ? $related_models[$row->id] : null;
if ($related_models_to_row)
$this->all[$i]->$related_field_name = reset($related_models_to_row);
$this->all[$i]->$related_field_name->all = $related_models_to_row;
if (isset($related_models[$this->id]))
$this->$related_field_name = $related_models[$this->id];
return $this;
// The two array helper functions used above from my_array_helper.php
function array_group_by($arr, $key, $index_by_col = false)
$re = array();
foreach ($arr as $v)
if (!isset($re[$v[$key]]))
$re[$v[$key]] = array();
if ($index_by_col === false)
$re[$v[$key]][] = $v;
else
$re[$v[$key]][$v[$index_by_col]] = $v;
return $re;
function array_column($arr, $key, $assoc = false)
if (empty($arr))
return array();
$tmp = array();
foreach ($arr as $k => $v)
if ($assoc === true)
$tmp[$k] = $v[$key];
elseif (is_string($assoc))
$tmp[$v[$assoc]] = $v[$key];
else
$tmp[] = $v[$key];
return $tmp;
【讨论】:
我想我找到了一个更好的解决方案,它也适用于多对多关系。 @Brainfeeder,你让我好奇,你发现了什么? 检查我发布的答案 :) 但是,如果您有大量相关对象,您的解决方案可能会更好。如果你需要它们,我现在的方式会加载它们......但是我需要数据就可以了。【参考方案2】:我现在有点探索 DM 并且我需要相同的功能。起初,来自另一个答案的 load_related
函数似乎是解决此问题的方法。
不过我做了一些进一步的研究。我找到了this 对另一个问题的回答,这让我开始思考是否没有办法仅自动填充某些关系。
嗯,有!!
如果您在模型中建立关系,则可以设置此“选项”。
//Instead of doing this:
var $has_many = array('user_picture');
//Do this
var $has_many = array(
'user_picture' => array(
'auto_populate' => TRUE,
),
);
现在图片将在用户对象中可用。
foreach ($u as $user)
foreach ($user->user_picture as $picture)
// Do your thing with the pictures
我在文档中的 this page 上找到了它。
享受吧!
【讨论】:
以上是关于DataMapper ORM - 如何获取所有模型和每个实例的相关数据的主要内容,如果未能解决你的问题,请参考以下文章
CodeIgniter DataMapper ORM 如何知道要应用哪组验证规则?
ORM/DAO/DataMapper/ActiveRecord/TableGateway 的区别?