【问题标题】:Doctrine 2 lazy loading issue in ZF2 projectZF2 项目中的 Doctrine 2 延迟加载问题
【发布时间】:2016-06-26 01:19:53
【问题描述】:

好的,一句话:帮助!

有些事情我想不通。在 ZF2 中,我使用了出色的 Doctrine Orm 模块。一切都很完美,但今天我发现了一些奇怪的东西。 我想我的某个地方一定有什么错误,但我找不到。或者也许在教义 2 中有一些我没有清楚理解的东西。

我已经映射了我的实体。当我有一个多对一关系而不指定 fetch 选项时,当我通过调用存储库上的 find() 方法获取一个实体时,我可以看到我的属性包含所生成的代理类的预期实例。但是当我在那个属性上调用 setter 时,它仍然包含代理类的 emtpy 实例???

Doctrine 似乎无法将实例链接到我的实体。就我而言,我从 find() 方法获得的实体是关系的所有者。

如果我在映射中指定 EAGER 上的 fetch 选项,则调用 find() 方法会返回一个实体,该实体的属性包含预期的关系中指定的类的实例。

有人遇到过同样的问题吗?

编辑: 好的,所以我创建了一个新的 ZF2 项目以确保没有任何干扰。 所以我有两个实体组和用户:

/**
 * Class Group
 * @package Application\Entity
 * @Entity
 * @Table("`group`")
 */
class Group
{
    /**
     * @Id
     * @GeneratedValue
     * @Column(type="integer", options={"unsigned"=true})
     */
    private $id;

    /**
     * @Column(type="string")
     */
    private $name;

    /**
     * @OneToMany(targetEntity="User", mappedBy="group")
     */
    private $users;
}

/**
 * Class User
 * @package Application\Entity
 * @Entity
 * @Table(name="user")
 */
class User
{
    /**
     * @Id
     * @GeneratedValue
     * @Column(type="integer", options={"unsigned"=true})
     */
    private $id;

    /**
     * @Column(type="string")
     */
    private $firstName;

    /**
     * @Column(type="string")
     */
    private $lastName;

    /**
     * @ManyToOne(targetEntity="Group", inversedBy="users")
     * @JoinColumn(name="groupId", referencedColumnName="id")
     */
    private $group;
}

当然,我在这两个类中都有所有的 getter 和 setter,但我没有将它们放在示例中以快速运行。

在我的控制器中,我做了一件非常简单的事情来在没有视图的情况下进行测试:

$user = $this->serviceLocator->get('doctrine.entitymanager.orm_default')->getRepository('Application\Entity\User')->find(1);
var_dump($user->getGroup());exit;

var_dump 显示:

object(DoctrineORMModule\Proxy\__CG__\Application\Entity\Group)[367]
  public '__initializer__' => 
    object(Closure)[362]
  public '__cloner__' => 
    object(Closure)[363]
  public '__isInitialized__' => boolean false
  private 'id' (Application\Entity\Group) => int 1
  private 'name' (Application\Entity\Group) => null

当然,我在数据库中添加了用户和组,并且我在表组的一个组中有一个 id 为 1 的用户。

也许我错过了一个选项或什么?为了配置 Doctrine 模块,我只是按照 github 上的文档进行操作,所以在这里我给出了注释驱动程序和我的实体的目录,当然还有数据库凭据。

【问题讨论】:

  • 这听起来像你错过了一些相当简单的东西,但如果没有更多细节就不可能说清楚。您可以通过显示一些代码来改进您的问题,尤其是相关的映射指令和您的存储库使用情况。
  • 好的,我添加了一些细节:我创建了一个迷你项目以确保每件事都是干净的。我把我的实体的代码和我的测试。再一次,如果我将 fetch="EAGER" 放在用户实体中用于组关系,一切都很好。但没有它......
  • 乍一看还不错。那么,接下来会发生什么? “调用该属性的 setter,然后它仍然包含代理类的 emtpy 实例”什么时候发生?
  • 这就是 Doctrine 的运作方式。通过用代理类替换实体类,Doctrine 可以延迟查询和水合该关联的昂贵任务,直到它真正需要为止。 Doctrine 默认为 fetch LAZY。但是,如果您使用选择EAGER fetch 选项,则返回实际的实体类。 Consider learning a little more about when to use it.

标签: doctrine-orm zend-framework2 lazy-loading


【解决方案1】:

这是完全可以预料的行为,因为教义延迟加载您的组实体。这是因为你所做的只是:

$user->getGroup();

我将尝试解释为什么您在这里只能获得代理:

您已从数据库中解析出的User 实体包含您的组实体的标识符(在本例中为id = 1)(此ID 来自您的user 表中的groupId 列)。当您调用getGroup 时,学说只会为您的Group 实体创建一个代理,并将其id 设置为1。到目前为止不需要数据库交互。

由于您没有向Group 实体请求任何其他内容,因此在这种简单情况下,代理就足够了。当您从您的组实体请求另一个属性(任何其他直接属性(组表中的列)但标识符)时,您会立即注意到差异。例如,尝试在您的组实体上调用 getName()。此属性尚未加载,因此教义将从数据库中的 group 表中获取带有 id = 1 的行,并将所有列作为属性加载(在这种情况下只有一个)在您的组对象中,然后它将返回请求名称的值。

所以像这样尝试一次:

$user->getGroup()->getName();

你的输出会很不一样。

我希望这能让行为更容易理解。

【讨论】:

  • 是的。事实上,今天我决定看一下由学说生成的代理类,我可以看到这一点。我误解了由于阅读速度快而导致的延迟加载方式,起初我认为在关系上调用 getter 足以让学说启动延迟加载。但确实有必要访问一个属性。感谢您的解释
猜你喜欢
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
  • 2014-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多