我正在开发一个 PHP Web 应用程序,并希望使用 Doctrine 2.0 来实现 ORM 功能。但是,我在处理一种特定类型的查询时遇到了很大的麻烦。
考虑一个包含 Foo 和 Bar 实体的简单域模型。一个 Foo 实体包含许多 Bar,并且一个 Bar 可能被标记为事件的。
/** @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;
}
执行 DQL 查询,例如 SELECT b FROM Bar l WHERE b.active = true AND b.foo = :foo
getActiveBar() 内似乎是解决方案,但是这样的查询不会检测到调用 EntityManager#flush() 之前对 Bar 所做的任何未完成的更改(因为 DQL 是针对数据库执行的)。
最佳答案
这可能不是世界末日。如果 Foo::bars 已加载,已被修改,并且尚未提交回数据库,则您唯一的选择就是迭代。
如果 Foo::bars 没有被加载,那么它肯定没有被修改,所以你不妨查询一下数据库。
(最后,如果 bar 已被加载、修改并提交回来,bars 集合的大小可能会决定提取或迭代是否会更好)
这让我很好奇,实体有一种方法可以判断集合成员是否已加载。
documentation似乎暗示代理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).
}
}
}
关于php - 原则 2 - 如何处理不同步的数据库/实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4587857/