【问题标题】:Doctrine EntityManager find object without retrieving all properties/collectionsDoctrine EntityManager 在不检索所有属性/集合的情况下查找对象
【发布时间】:2016-03-04 23:51:05
【问题描述】:

假设我有一个名为User 的实体,它具有一些属性,例如firstName, lastName, agePosts 的集合。

有没有办法使用EntityManagerFind 方法加载这个User 实体而不加载所有属性/集合?

我正在使用REST API 来检索User,并且我想分开通话:

  1. api/user/1 - 应仅使用 firstName, lastName and age 检索 User 对象。
  2. api/user/1/posts - 应该检索带有属性的 User 对象和 Posts 的集合。

我知道我可以使用 QueryBuilder 并创建单独的方法来检索所需的数据,但我希望这样:

场景:

api/user/1

$userId = 1;
$user = getEntityManager()->find('entity\User', $userId);
return $user; // should only load the firstName, lastName, age properties.

api/user/1/posts

$userId = 1;
$user = getEntityManager()->find('entity\User', $userId);
return $user->getPosts(); // should load the firstName, lastName, age properties and the collection of posts.

我已经尝试过内置 Doctrine 的“Extra Lazy Load”功能,但没有任何结果。

我的代码:

<?php
/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name = "USER")
 * 
 * @JMS\ExclusionPolicy("all")
 * @JMS\AccessorOrder("custom", custom = { "id", "firstName", "lastName" })
 */
class User {

    /**
     * @ORM\Id
     * @ORM\Column(name = "id", type = "integer", options={"unsigned"=true})
     * @ORM\GeneratedValue(strategy = "IDENTITY")
     * @JMS\SerializedName("id")
     * @JMS\Expose
     * @JMS\Type("integer")
     * @var int
     */
    private $id;

    /**
     * @ORM\Column(name = "firstName", type = "string", length = 255)
     * @JMS\SerializedName("firstName")
     * @JMS\Expose
     * @JMS\Type("string")
     * @var string
     */
    private $firstName;

    /**
     * @ORM\Column(name = "lastName", type = "string", length = 255)
     * @JMS\SerializedName("lastName")
     * @JMS\Expose
     * @JMS\Type("string")
     * @var string
     */
    private $lastName;

    /**
     * @ORM\OneToMany(targetEntity = "Post", mappedBy = "user", cascade = { "persist" }, fetch="LAZY")
     * @JMS\Expose
     * @var ArrayCollection<Post>
     */
    private $posts;

    public function getId() {
        return $this->id;
    }

    public function getFirstName() {
        return $this->firstName;
    }

    public function getLastName() {
        return $this->lastName;


    public function getPosts() {
        return $this->posts->toArray();
    }

}

帖子总是在获取用户对象后加载,即使我使用获取类型lazy或extra_lazy。

【问题讨论】:

  • 只要您使用延迟加载的集合定义了您的实体(例如,您的用户实体中的帖子)并且您没有访问未加载的用户的帖子。所以你必须提供更多细节,但我们为让它运行付出了很多努力,所以我也许可以提供帮助。
  • @LBA 添加了用户类!
  • 大胆猜测:也许延迟加载会受到$this-&gt;posts-&gt;toArray() 的阻碍(你的转换用例是什么?我总是将它们保留为ArrayCollection)。您能否尝试将帖子返回为$this-&gt;posts,并确保没有人可以访问帖子。
  • @k0pernikus 删除 toArray() 或 getPosts() 方法都不起作用...我只是调用 getEntityManager()->find('namespace', $id);当我在 JSON 中回显时,它还会显示帖子...
  • 您是否对整个用户对象进行了 JSON 编码?可能是序列化触发了延迟加载。

标签: php doctrine-orm doctrine


【解决方案1】:

为什么不使用序列化组呢?

您可以注释您的组(例如 {'default'} 和 {'collection'} 甚至更具体的 {'posts'}。

然后您只需在 Controller 中设置您的序列化上下文,并且只会序列化与 Group 相关的属性。

另见documentation

【讨论】:

  • 感谢您的推荐。我猜肯定会使用它,但我猜这仍然会触发延迟加载?
  • 给出的解决方案是根据请求的操作执行不同排除策略的正确方法。您还应该查看@MaxDepth 以限制您的帖子集合条目的深度。
  • 只要你不访问lazy-loadable属性,它就不会被加载。将组与 JMS 序列化程序一起使用可避免调用不必要的属性,从而避免它们的加载。
【解决方案2】:

您应该编写正确的 dql/querybuilder 查询并仅选择您所需的字段。

仅使用 $user-&gt;getPosts() 返回 API 上的所有帖子是不安全的 - 您需要在此处进行分页。

您也可以使用JMSSerializerBundle。它使您可以选择为实体定义所需的属性。

【讨论】:

  • 添加了用户类!
  • 啊,所以您已经使用了它;)您在原始问题中没有提到这一点。但我的回答仍然正确 - You should write proper dql/querybuilder query and select only required for You fields.
猜你喜欢
  • 2015-03-27
  • 1970-01-01
  • 2017-07-28
  • 2010-10-09
  • 1970-01-01
  • 2012-08-21
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多