Symfony2 -检查学说实体关联是否已经初始化/加载而没有触发Lazyload



我有一个名为foo的实体,它与一个名为bar的实体有一个OneToMany关联,该实体可作为$foo->getBar()(一个ArrayCollection)访问。通常调用$foo->getBar()会触发关联的bar实体的延迟加载(如果它们最初没有连接)。

如何检查bar是否已加载而不触发延迟加载?我不需要关联的实体,如果它们最初没有加载,我也不希望它们加载,我只想知道它们是否加载。

fooRepository中,我有一个叫做getFooWithBar()的方法,它有一个连接,它将所有bars加载为ArrayCollection,并返回foo和所有相关的bar实体。但是,如果我只是用一个简单的查询调用一个更简单的方法,如getFooById(), bar实体没有加载连接,因此它们不包含在$foo中。

所以在另一个控制器中,我有$foo,我想检查getBar()是否已经加载了相关实体,但我不想触发延迟加载。如果它没有关联的实体,我就不想要它们。我只需要知道它们是否已经加载。

注意:我也不想为所有实例关闭实体关联的延迟加载

对OneToMany的逆侧不起作用的方法

我把这个神奇的getter方法放在了我的实体中:

public function __get($property) {
    return isset($this->$property) ? $this->$property : null;
}

理论上可以让我检查是否设置了属性(或者它是否仍然是默认的私有声明)。当我的实体是所有者的时候,这是有效的。但如果是逆边,$this->属性永远不会设置。Doctrine做了一些奇特的东西,所以当你做getProperty()时,它会在其他地方查看数据。我发现了这一点,因为这个函数工作时,它是拥有的一方(它返回关联实体的代理),但它返回null时,关联实体是由另一个实体拥有。

经过多年的测试我们的代码(响应原则的变化),下面是我们可以想出的最好的解决方案来检查一个关联是否已经加载,没有触发LazyLoad。这些东西都没有在Doctrine中记录(很不幸),所以你必须查看源代码和/或使用代码。

的解决方案

最后,有许多不同类型的不同的关联,可以从* many (PersistentCollection)或*ToOne关联(代理或直接实体)加载。这意味着我们需要创建一个方法来检查所有可能性(我们目前在应用中知道的)。我们创建了一个trait,并将其添加到所有实体中,这样我们就可以调用$entity->isLoaded($propertyName)来检查它是否加载。

public function isLoaded($property)
{
    // *ToMany Association are PersistentCollection and will have the isInitialized property as true if it's loaded
    if ($this->{$property} instanceof PersistentCollection) {
        return $this->{$property}->isInitialized();
    }
    // *ToOne Associations are (sometimes) Proxy and will be marked as __isInitialized() when they are loaded
    if ($this->{$property} instanceof Proxy) {
        return $this->{$property}->__isInitialized();
    }
    // NOTE: Doctrine Associations will not be ArrayCollections. And they don't implement isInitalized so we really
    // can tell with certainty whether it's initialized or loaded. But if you join entities manually and want to check
    // you will need to set an internal mapper that records when you've loaded them. You could return true if count > 0 
    if ($this->{$property} instanceof ArrayCollection) {
        //  NOTE: __isLoaded[$property] is an internal property we record on the Setter of special properties we know are ArrayCollections
        return (!empty($this->__isLoaded[$property]) || $this->{$property}->count() > 0);
    }
    // NOTE: there are never any Collections that aren't ArrayCollection or PersistentCollection (and it does no good to check because they won't have isInitialized() on them anyway
    // If it's an object after the checks above, we know it's not NULL and thus it is "probably" loaded because we know it's not a Proxy, PersistentCollection or ArrayCollection
    if (is_object($this->{$property})) {
        return true;
    }
    // If it's not null, return true, otherwise false. A null regular property could return false, but it's not an Entity or Collection so indeed it is not loaded.
    return !is_null($this->{$property});
}

当你加载foo对象时,bar将是DoctrineORMPersistentCollection的一个实例。您可以调用此集合的isInitialized()方法来查看是否已初始化。

对于ArrayCollection:

$initialized = $foo->getBar()->isInitialized();

如果您有最新版本的Doctrine,您可以尝试对列进行额外的延迟加载。

最新更新