首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Doctrine 2中的代理是什么?

Doctrine 2中的代理是什么?
EN

Stack Overflow用户
提问于 2011-02-08 00:39:04
回答 2查看 33.8K关注 0票数 114

我刚刚读完了Doctrine 2的所有文档,我启动了自己的沙箱,我理解了大部分原理,但仍然有一个问题,我在文档中找不到任何完整的解释。

  1. 什么是Proxy类?
  2. 我应该在什么时候使用它们而不是实体?

据我所知,代理类添加了一个层,让您可以向实体添加一些其他功能,但为什么要使用代理而不是在entity类中实现方法本身?

EN

回答 2

Stack Overflow用户

发布于 2011-02-08 04:15:25

更新

此答案包含有关代理对象和部分对象之间差异的错误信息。有关更多详细信息,请参阅@Kontrollfreak的答案:https://stackoverflow.com/a/17787070/252591

只要查询没有返回创建实体所需的所有数据,就会使用代理对象。想象一下下面的场景:

代码语言:javascript
复制
@Entity
class User {
     @Column protected $id;
     @Column protected $username;
     @Column protected $firstname;
     @Column protected $lastname;

     // bunch of setters/getters here
}

DQL query:

SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id

如您所见,此查询不返回firstnamelastname属性,因此不能创建User对象。创建不完整的实体可能会导致意外错误。

这就是为什么Doctrine会创建支持延迟加载的UserProxy对象。当您尝试访问firstname属性(未加载)时,它将首先从数据库加载该值。

我的意思是为什么我要使用代理?

您应该始终像根本不使用代理对象一样编写代码。它们可以被视为Doctrine使用的内部对象。

为什么惰性加载不能在实体本身中实现?

从技术上讲,它可能是,但看看一些随机代理对象的类。它充满了肮脏的代码。在你的实体中有一个干净的代码是很好的。

你能给我提供一个用例吗?

您正在显示最新的25篇文章的列表,并且希望显示第一篇文章的详细信息。它们中的每一个都包含大量文本,因此获取所有这些数据将是对内存的浪费。这就是为什么你不去获取不必要的数据。

代码语言:javascript
复制
SELECT a.title, a.createdAt
FROM Entity\Article a
ORDER BY a.createdAt DESC
LIMIT 25

$isFirst = true;
foreach ($articles as $article) {
    echo $article->getTitle();
    echo $article->getCreatedAt();

    if ($isFirst) {
        echo $article->getContent(); // Article::content is not loaded so it is transparently loaded 
                                     // for this single article.

        $isFirst = false;
    }
}
票数 160
EN

Stack Overflow用户

发布于 2013-07-22 20:02:00

代理

Doctrine代理只是一个包装器,它扩展了一个实体类来为它提供延迟加载。

默认情况下,当您向实体管理器请求一个与另一个实体相关联的实体时,不会从数据库加载相关联的实体,而是包装到一个代理对象中。然后,当您的应用程序请求此代理实体的属性或调用该实体的方法时,Doctrine将从数据库加载该实体(请求ID时除外,代理始终知道该ID)。

这对于你的应用程序来说是完全透明的,因为代理扩展了你的实体类。

默认情况下,如果您不在查询中提取关联,或者将获取模式设置为EAGER,Doctrine会将它们作为惰性加载代理进行水合。

现在我必须补充这一点,因为我没有足够的名气来到处评论:

不幸的是,Crozin的回答包含错误信息。

如果您执行如下DQL查询

代码语言:javascript
复制
SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id

你得到的不是一个(代理的)实体对象,而是一个关联数组。所以不可能延迟加载任何额外的属性。

考虑到这一点,人们得出结论,用例示例也不会起作用。为了将$article作为对象访问,必须将DQL更改为如下所示:

代码语言:javascript
复制
SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25

getContent()返回的属性必须是一个关联,这样才不会加载所有25个实体的内容属性。

部分对象

如果你想要部分加载不是关联的实体属性,你必须明确地告诉这个Doctrine:

代码语言:javascript
复制
SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id

这将为您提供一个部分加载的实体对象。

但是要注意,部分对象不是代理!延迟加载不适用于它们。因此,使用部分对象通常是危险的,应该避免使用。阅读更多:Partial Objects — Doctrine 2 ORM 2 documentation

票数 88
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4923817

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档