简体   繁体   English

在理论中加载相关实体的子集

[英]Load subset of related entities in doctrine

I am not sure if what I want to do is possible or not, but I can't find any documentation on it. 我不确定我想做的事是否可行,但是找不到任何文档。 Hopefully I am just looking in the wrong places. 希望我只是在错误的地方寻找。

What I would like to do is load an object that will always load a subset of a related object. 我想做的是加载一个将始终加载相关对象子集的对象。 some background - I want to keep a history of the contacts that a user deletes, so when a contact is deleted, I set a isDeleted column in the db to true. 一些背景-我想保留用户删除的联系人的历史记录,因此当删除联系人时,我将数据库中的isDeleted列设置为true。 I will rarely want to load the deleted contacts, so I will worry about that later. 我很少要加载已删除的联系人,因此以后会担心。 But when I load a user, and then load the contacts (in my case by serializing the whole user object), all of the contacts are loaded including the deleted ones. 但是,当我加载一个用户,然后加载联系人(在我的情况下,通过序列化整个user对象)时,所有的联系人都被加载,包括已删除的联系人。 So I would like to only load the contacts that have not been deleted yet. 因此,我只想加载尚未删除的联系人。 This is what I have right now, and I don't know why it is not working. 这就是我现在所拥有的,而且我不知道为什么它不起作用。

use Doctrine\Common\Collections\Criteria,
    Doctrine\Common\Collections\ArrayCollection;

class User{
/**
 * @ORM\OneToMany(targetEntity="Contacts", mappedBy="user", cascade={"persist"}, fetch="EXTRA_LAZY")
 * @ORM\JoinColumn(name="contact_id", referencedColumnName="contact_id")
 */
private $contacts;

public function __construct(){
    $this->contacts = new ArrayCollection();
}

/**
 * Get contacts
 *
 * @return \Doctrine\Common\Collections\ArrayCollection
 */
public function getContacts()
{
    // This is where I am filtering the contacts
    $criteria = Criteria::create()
    ->where(Criteria::expr()->eq("isDeleted", false));
    return $this->contacts->matching($criteria);
}

And then I am loading and serializing a user using the JMS Serializer and FOSRest in my Controller. 然后,使用控制器中的JMS序列化器和FOSRest加载并序列化用户。

public function getUserAction($slug){
    $data = $this->getDoctrine()->getRepository('MyCoreBundle:User')->find($slug);
    $view = $this->view($data, 200);

    return $this->handleView($view);
}

And the result is the following JSON: 结果是以下JSON:

{
userId: 7,
creationDate: "2014-07-28T22:05:43+0000",
isActive: true,
username: "myUser",
contacts: [
    {
        contactId: 23,
        firstName: "Jim",
        lastName: "Bin",
        email: "zzz@zzz.com",
        phone: "1231231231",
        isDeleted: true
    }
]
}

I am not sure why this is still loading the deleted user. 我不确定为什么它仍在加载已删除的用户。 If I do the filtering in my controller instead of the Entity class, then the filtering works. 如果我在控制器中而不是在Entity类中执行过滤,则过滤有效。 But I don't want to have to do that everywhere in my application that a contact may be loaded. 但是我不想在我的应用程序中到处需要加载联系人。 If I could get something working in the Entity class, that would be ideal. 如果我可以在Entity类中工作,那将是理想的。 Has anyone done something similar that could work? 有没有人做过类似的事情可能起作用?

I'm using Symfony 2.3 我正在使用Symfony 2.3

I think your problem is that getContacts doesn't actually get called when you fetch a User from its repository, that's done using a standard Doctrine query, and since User and Contacts are related regardless of whether a Contact has been deleted, they all come across. 我认为您的问题是,从标准存储库中获取用户时,实际上不会调用getContacts ,这是使用标准的Doctrine查询完成的,并且由于User和Contacts是相关的,无论是否删除了Contact,它们都会碰到。 One solution would be to create your own UserRepository with a findUserWithActiveContacts() method, which executes a more appropriate query, and use that instead. 一种解决方案是使用findUserWithActiveContacts()方法创建您自己的UserRepository,该方法执行更合适的查询,而改用该查询。

For example: 例如:

UserRepository.php UserRepository.php

namespace Demo\MyBundle\Entity;

use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository
{
    public function findWithActiveContacts($slug)
    {
        $result= $this->createQueryBuilder('u')
            ->join('u.contacts', 'c')
            ->select('u,c')
            ->where('c.isDeleted = false')
            ->andWhere('u.slug = :slug')
            ->setParameter('slug', $slug)
            ->getQuery()
            ->getResult();

        return $result;
    }
}

And hook up the entity to the new repository: 并将实体连接到新的存储库:

User.php user.php的

class User{
/**
 * @ORM\OneToMany(targetEntity="Contacts", mappedBy="user", cascade={"persist"}, fetch="EXTRA_LAZY")
 * @ORM\JoinColumn(name="contact_id", referencedColumnName="contact_id")
 * @ORM\Entity(repositoryClass="Demo\MyBundle\Entity\UserRepository")
 */

And then in the controller: 然后在控制器中:

public function getUserAction($slug){
    $data = $this->getDoctrine()->getRepository('MyCoreBundle:User')->findWithActiveContacts($slug);
    $view = $this->view($data, 200);

    return $this->handleView($view);
}

So as long as you use findWithActiveContacts instead of find you should always get just the non-deleted contacts, without having to change anything else. 因此,只要您使用findWithActiveContacts而不是find ,就应该始终只获取未删除的联系人,而无需更改其他任何内容。

I think you could probably override find itself in your customer Repository if you wanted, but for you that would just change the name of the method you're calling, and I'd be worrying that other code (eg stuff which fetches entities for forms) would start using it, which might be what you want but also might have unpredictable consequences. 我想你大概可以忽略find自己的客户资源库,如果你想要的,但你只想改变你调用该方法的名称,我会担心其他代码(例如东西它取实体形式)将开始使用它,这可能是您想要的,但也可能会带来不可预测的后果。

The official Doctrine way of tweaking all queries in this sort of fashion is to use Filters , which actually slips in an extra where clause to everything which goes through Doctrine. 以这种方式调整所有查询的Doctrine官方方法是使用Filters ,它实际上为通过Doctrine的所有内容增加了一个where子句。 This is how the SoftDeleteable extension does it. 这就是SoftDeleteable扩展的工作方式。

I'd highly recommend the Soft-Deleteable extension. 我强烈建议您使用Soft-Deleteable扩展程序。 You'd have to use a deletedAt field which is null when the object is not deleted, and a timestamp if deleted. 您必须使用deletedAt字段,如果未删除对象,则该字段为null ;如果删除则为timestamp

It goes like this: 它是这样的:

/**
 * @ORM\Entity
 * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
 */
class User
{
    /**
     * @ORM\Column(name="deletedAt", type="datetime", nullable=true)
     */
    private $deletedAt;

    public function getDeletedAt()
    {
        return $this->deletedAt;
    }

    public function setDeletedAt($deletedAt)
    {
        $this->deletedAt = $deletedAt;
    }

}

Have a look at this extension here: Soft-Deleteable Extension 在这里查看此扩展: 可删除软扩展

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM