问题描述
我刚刚阅读了所有学说2文档,我开始了自己的沙箱,我了解了大多数原理,但是仍然有一个问题,我找不到文档中的任何完整解释.
.- 什么是Proxy类?
- 我什么时候应该将它们用于实体?
据我了解,代理类添加了一层以让您在实体中添加其他功能,但是为什么要使用代理而不是在实体类中实现方法自己?
推荐答案
更新
此答案包含有关代理对象和部分对象之间差异的错误信息.有关更多详细信息,请参见 @kontrollfreak的答案: https://stackoverflow.com/a/a/a/177787070/252591
当您的查询不返回创建实体所需的所有数据时,都会使用代理对象.想象以下方案:
@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
您可以看到此查询不会返回firstname和lastname属性,因此您不能创建User对象.创建不完整的实体可能导致意外错误.
这就是为什么学说将创建支持懒惰加载的对象的原因.当您尝试访问firstname属性(未加载)时,它将首先从数据库加载该值.
我的意思是为什么要使用代理?
您应该始终像根本不使用代理对象一样写代码.它们可以视为学说使用的内部对象.
为什么不能在有效本身中实现懒惰加载?
从技术上讲,这可能是,但要看一下一些随机代理对象的类.它充满了肮脏的代码,呃.在您的实体中有一个干净的代码很高兴.
您可以给我用例吗?
您正在显示最新25篇文章的列表,并且您想显示第一篇文章的详细信息.他们每个人都包含大量文本,因此获取所有数据将浪费记忆.这就是为什么您不获取不必要的数据.
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; } }
其他推荐答案
代理
学说代理只是一个包装器,它扩展了实体类,以提供懒惰的负载.
默认情况下,当您向实体管理器询问与另一个实体关联的实体时,关联的实体不会从数据库中加载,而是包裹到代理对象中.当您的应用程序请求属性或调用该代理实体的方法时,学说将从数据库中加载实体(除非您请求ID(始终是代理人知道的ID)).
由于代理扩展了您的实体类,因此对您的应用程序完全透明.
学说默认情况下,如果您不在查询中JOIN,则默认情况下将作为懒负载代理,或将获取模式设置为EAGER.
现在我必须添加它,因为我没有足够的声誉在任何地方发表评论:
不幸的是,Crozin的答案包含错误信息.
如果您执行DQL查询,例如
SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id
您不会得到(代理)实体对象,而是一个关联数组.因此,不可能懒惰加载任何其他属性.
考虑到这一点,得出的结论是,用例示例也无法正常工作. 必须将DQL更改为类似的东西才能访问$article作为对象:
SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25
,getContent()返回的属性必须是关联,以便不加载 all> All 25实体的内容属性.
部分对象
如果要部分加载非关联的实体属性,则必须明确地说明此学说:
SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id
这为您提供了部分加载的实体对象.
但要注意部分对象不是代理!懒惰加载不适用于他们.因此,使用部分对象通常是危险的,应避免.阅读更多信息:部分2文档
问题描述
I just finished reading all the Doctrine 2 documentation, I started my own sandbox, I understood most of the principes, but there is still a question and I couldn't find any complete explanation in the doc.
- What are Proxy classes?
- When should I use them over entities?
As far as I understand, proxy classes add a layer to let you add some other features to your entities, but why use a proxy instead of implementing the methods themselves in the entity class?
推荐答案
UPDATE
This answer contains wrong information about differences between proxy objects and partial objects. See @Kontrollfreak's answer for more details: https://stackoverflow.com/a/17787070/252591
Proxy objects are used whenever your query doesn't return all data required to create an entity. Imagine following scenario:
@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
As you can see this query doesn't return firstname and lastname properties, therefore you cannot create User object. Creation of incomplete entity could lead to unexpected errors.
That's why Doctrine will create UserProxy object that supports lazy loading. When you'll try to access firstname property (which is not loaded) it will first load that value from database.
I mean why should I use a proxy ?
You should always write your code as if you didn't use proxy objects at all. They can be treated as internal objects used by Doctrine.
Why the lazy loading can't be implemented in the Entitiy itself?
Technically it could be but take a look at some random proxy object's class. It's full of dirty code, ugh. It's nice to have a clean code in your entities.
Can you provide me an use case?
You're displaying a list of latest 25 articles and you want to display a details of the first one. Each of them contain a large amount of text, so fetching all that data would be a waste of memory. That's why you don't fetch unnecessary data.
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; } }
其他推荐答案
Proxies
A Doctrine proxy is just a wrapper that extends an entity class to provide Lazy Loading for it.
By default, when you ask the Entity Manager for an entity that is associated with another entity, the associated entity won't be loaded from the database, but wrapped into a proxy object. When your application then requests a property or calls a method of this proxied entity, Doctrine will load the entity from the database (except when you request the ID, which is always known to the proxy).
This happens fully transparent to your application due to the fact that the proxy extends your entity class.
Doctrine will by default hydrate associations as lazy load proxies if you don't JOIN them in your query or set the fetch mode to EAGER.
Now I must add this because I don't have enough reputation to comment everywhere:
Unfortunately, Crozin's answer contains misinformation.
If you execute a DQL query like
SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id
you won't get a (proxied) entity object, but an associative array. So it's not possible to lazy load any additional properties.
With this in mind, one comes to the conclusion that the use case example won't work either. The DQL would have to be changed to something like this in order to access $article as object:
SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25
And the property returned by getContent() would have to be an association in order not to load the content properties of all 25 entities.
Partial Objects
If you want to partially load entity properties that are not associations, you have to tell this Doctrine explicitly:
SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id
This gives you a partially loaded entity object.
But beware that partial objects are not proxies! Lazy Loading doesn't apply to them. Therefore, using partial objects is generally dangerous and should be avoided. Read more: Partial Objects — Doctrine 2 ORM 2 documentation