我正在开发一个PHP Web应用程序,我希望将Doctrine 2.0用于ORM功能。但是,我遇到了一个特定类型的查询时遇到的重大问题。
考虑一个包含Foo和Bar Entities的简单域模型。 Foo实体包含许多条形,条形可能被标记为活动。
/** @Entity */
class Foo
{
/** @OneToMany(targetEntity="Bar", mappedBy="foo") */
protected $bars;
/** Returns Bars marked as active. */
public function getActiveBars()
{
// XXX What goes here?
}
}
/** @Entity */
class Bar
{
/** @ManyToOne(targetEntity="Foo", inversedBy="bar") */
protected $foo;
/** @Column(type="boolean") */
protected $active;
/** ...setter omitted for clarity... */
}
我的问题是:应该在getActiveBars
方法中放置哪些代码?
以下代码可以正常工作,但当数据库中有许多非活动Bar对象时,性能将成为问题。迭代Bar集合会导致对数据库执行大型查询。
function getActiveBars()
{
$ret = array();
foreach($this->bars as $bar) {
if ($bar->isActive()) $ret[] = $bar;
}
return $ret;
}
在getActiveBar()中执行诸如SELECT b FROM Bar l WHERE b.active = true AND b.foo = :foo
之类的DQL查询似乎是解决方案,但是这样的查询将不会检测在调用EntityManager #flush()之前对Bar进行的任何未完成的更改(因为执行了DQL)反对数据库)。
答案 0 :(得分:3)
这可能不是世界末日。如果加载Foo :: bars,已被修改,并且尚未提交回数据库,则唯一的选择是迭代。
如果没有加载Foo :: bars,那么它肯定没有被修改过,所以你也可以查询数据库。
(最后,如果已经加载,修改和提交了条形图,条形图集合的大小将决定是否更好地获取或迭代)
这让我感到好奇的是,实体有办法判断某个集合的成员是否已加载。
documentation似乎意味着Proxied ArrayCollection(在您的示例中为Foo:bars)将不通过instanceof ArrayCollection
测试。因此,您可能会尝试变得如此聪明:
class Foo {
public function getActiveBars(){
if ($this->bars instanceof \Doctrine\Common\Collection\ArrayCollection){
//get active bars by iterating over $this->bars
}else{
//get active bars by DQL, and avoid loading $this->bars (for now).
}
}
}