简体   繁体   English

如何发出仅当实体与具有ManyToMany的另一个实体相关的DQL请求?

[英]How to make a DQL request that takes entity only if they are related to another entity with ManyToMany?

I have my User linked to Event entity. 我的用户链接到事件实体。 Basically, users may wanna go to several events and, through a many to many, I'm registering who want to go to X event. 基本上,用户可能想参加几个活动,并且通过许多很多人,我正在注册谁想参加X活动。

I need to build a Query with Doctrine that pick up users if they are available (available set to 1) OR if they plan on going to an event depending on their location ( I got this one too ). 我需要使用Doctrine构建一个查询,以查询用户是否可用(将其设置为1),或者是否打算根据其位置参加某个活动(我也知道了)。 The first conditions is fine. 第一个条件很好。 But for the second one, I need to make sure that the user has at least one event he wants to go to, registered in the many to many relation: eventNotified. 但是对于第二个事件,我需要确保用户至少有一个他想参加的事件,并以多对多关系进行了注册:eventNotified。

In Php I would do a foreach loop and then condition if the $user->getEventNotified() is not an empty array ( or null ) but that would make me pull up too many results. 在Php中,我将执行foreach循环,然后确定$ user-> getEventNotified()是否不是空数组(或null),但这会使我产生太多结果。 I want to select it with SQL or DQL 我想用SQL或DQL选择它

How can I do that? 我怎样才能做到这一点?

Here is what I have achieved so far, I just need to add a OR condition if the user wants to go an event (is eventNotified not null ?): 到目前为止,这是我已经实现的目标,如果用户想要进行事件(eventNotified不是null),我只需要添加一个OR条件:

//We only want to return users nearby who are available OR who 
    $qb = $this->_em->getRepository( 'Entity\User' )->createQueryBuilder('a');

    $qb->andwhere( 'a.latitude > :minLat' );
    $qb->andWhere( 'a.latitude < :maxLat' );
    $qb->andWhere( 'a.longitude > :minLng' );
    $qb->andWhere( 'a.longitude < :maxLng' );
    $qb->andWhere( 'a.available = 1' );

    $qb->add( 'orderBy', $qb->expr()->sum( 'a.latitude - :lat', 'a.longitude - :lng' ));

    $array = array(
         'minLat' => $minLat,
         'maxLat' => $maxLat,
         'minLng' => $minLng,
         'maxLng' => $maxLng,
         'lat'    => $lat,
         'lng'    => $lng
    );

    $qb->setParameters( $array );

    // $qb->setFirstResult( $offset );
 //    $qb->setMaxResults( $limit );

    // print_r(array(
    //     'sql'        => $qb->getQuery()->getSQL(),
    //     'parameters' => $qb->getQuery()->getParameters(),
    // ));
    $usersNearby = $qb->getQuery()->getResult();

    return $usersNearbt;

And here is my user entity: 这是我的用户实体:

class User
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false, unique=true)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="fb_id", type="bigint", nullable=false, unique=true)
     */
    private $fb_id;

    /**
     * @var string
     *
     * @ORM\Column(name="firstname", type="string", length=100, nullable=false, unique=false)
     */
    private $first_name;

    /**
     * @var string
     *
     * @ORM\Column(name="lastname", type="string", length=100, nullable=true, unique=false)
     */
    private $last_name;

    /**
     * @var string
     *
     * @ORM\Column(name="email", type="string", length=255, nullable=true, unique=true)
     */
    private $email;

    /**
     * @var integer
     *
     * @ORM\Column(name="notation", type="integer", nullable=true, unique=true)
     */
    private $notation;

    /**
     * Bidirectional - Many users have Many favorite comments (OWNING SIDE)
     *
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="Entity\Category", inversedBy="userInterests")
     */
    private $interests;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="Entity\User", cascade={"persist"})
     * @ORM\JoinTable(name="friends",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="friend_user_id", referencedColumnName="id")}
     *      )
     **/
    private $friends;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="Entity\Request", mappedBy="user", cascade={"remove"}, orphanRemoval=true)
     * @ORM\JoinColumn(nullable=true)
     */
    private $requests;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="Entity\Request", mappedBy="friend", cascade={"remove"}, orphanRemoval=true)
     * @ORM\JoinColumn(nullable=true)
     */
    private $notifications;

    /**
     * Bidirectional - Many users have notified they want to go to different events (OWNING SIDE)
     *
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="Entity\Event", inversedBy="userNotified", cascade={"persist"})
     */
    private $eventNotified;

    /**
     * @var integer
     *
     * @ORM\Column(name="age", type="integer", length=3, nullable=true, unique=false)
     */
    private $age;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text", nullable=true, unique=false)
     */
    private $description;

    /**
     * @var string
     *
     * @ORM\Column(name="picture", type="string", length=300, nullable=true, unique=false)
     */
    private $picture;

    /**
     * @var string
     *
     * @ORM\Column(name="genre", type="string", length=10, nullable=true, unique=false)
     */
    private $genre;

    /**
     * @var boolean
     *
     * @ORM\Column(name="isregistered", type="boolean", length=1, nullable=false, unique=false)
     */
    private $registered;

    /**
     * @var string
     *
     * @ORM\Column(name="latitude", type="decimal", length=64, precision=25, scale=20, nullable=true, unique=false)
     */
    private $latitude;

    /**
     * @var string
     *
     * @ORM\Column(name="longitude", type="decimal", length=64, precision=25, scale=20, nullable=true, unique=false)
     */
    private $longitude;

    /**
     * @var \Entity\Security_Key
     *
     * @ORM\OneToOne(targetEntity="Entity\Security_Key", cascade={"persist","remove"}, orphanRemoval=true)
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="private_key_id", referencedColumnName="id", unique=true, onDelete="SET NULL")
     * })
     */
    private $private_key;

    /**
     * @var boolean
     *
     * @ORM\Column(name="isavailable", type="boolean", length=1, nullable=false, unique=false)
     */
    private $available = 0;
...

EDIT: 编辑:

Thanks to the solution below I had it working with a little tweak ( and a few optimisations ): 由于下面的解决方案,我进行了一些微调(以及一些优化):

    $qb = $this->getEntityManager()->createQueryBuilder();

    $qb->select( 'USER', 'EVENT', 'c', 'p' )
        ->from( 'Entity\User',  'USER' )
        ->innerJoin( 'USER.eventNotified', 'EVENT' )
        ->leftJoin( 'EVENT.categories', 'c' )
        ->leftJoin( 'EVENT.place', 'p' )
        ->add('where', $qb->expr()->andX(
                $qb->expr()->between('USER.latitude', ':minLat', ':maxLat'),
                $qb->expr()->between('USER.longitude', ':minLng', ':maxLng')
            )
        )
        ->add( 'orderBy', $qb->expr()->sum( 'USER.latitude - :lat', 'USER.longitude - :lng' ) );

    $array = array(
         'minLat' => $minLat,
         'maxLat' => $maxLat,
         'minLng' => $minLng,
         'maxLng' => $maxLng,
         'lat'    => $lat,
         'lng'    => $lng
    );

    $qb->setParameters( $array );

    $usersNearby = $qb->getQuery()->getResult();

You need to join to the ManyToMany entity. 您需要加入ManyToMany实体。 If the user hasn't got any Event related (by your User.eventNotified property), he/she won't be retrieved. 如果用户没有任何与事件相关的事件 (通过您的User.eventNotified属性),则不会检索到他/她。 I also would build the where conditions using the Expr class ofered by QueryBuilder : 我也将建立使用QueryBuilder的 ofered后面的Expr类的地方条件:

$qb = $this->getEntityManager()->createQueryBuilder();

$qb->select( 'USER' )
    ->from( 'Entity\User',  'USER' )
    ->innerJoin( 'USER.eventNotified' )
    ->where( 
        $qb->expr()->andX(
            $qb->expr()->gt( 'USER.latitude', ':minLat' ),
            $qb->expr()->lt( 'USER.latitude', ':maxLat' ),
            $qb->expr()->gt( 'USER.longitude', ':minLng' ),
            $qb->expr()->lt( 'USER.longitude', ':maxLng' ),
            $qb->expr()->eq( 'USER.available', 1 )
        )
    ); 

(...) //orderBy and parameters

Check the QueryBuilder documentation . 查看QueryBuilder文档

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

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