【问题标题】:How to make a DQL request that takes entity only if they are related to another entity with ManyToMany?仅当实体与具有 ManyToMany 的另一个实体相关时,如何发出接受实体的 DQL 请求?
【发布时间】:2014-02-02 05:34:28
【问题描述】:

我将我的用户链接到事件实体。基本上,用户可能想参加几个活动,通过多对多,我正在注册谁想参加 X 活动。

我需要使用 Doctrine 构建一个查询来获取用户是否可用(可用设置为 1)或者他们是否计划根据他们的位置参加活动(我也有这个)。第一个条件很好。但是对于第二个,我需要确保用户至少有一个他想去的事件,注册在多对多关系中:eventNotified。

在 Php 中,我会执行一个 foreach 循环,然后判断 $user->getEventNotified() 是否不是空数组(或 null ),但这会使我得到太多结果。我想用 SQL 或 DQL 选择它

我该怎么做?

这是我到目前为止所取得的成就,如果用户想要参加一个活动,我只需要添加一个 OR 条件(eventNotified 不是 null 吗?):

//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;

这是我的用户实体:

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;
...

编辑:

感谢下面的解决方案,我对其进行了一些调整(和一些优化):

    $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();

【问题讨论】:

    标签: php sql symfony doctrine-orm dql


    【解决方案1】:

    您需要加入 ManyToMany 实体。如果用户没有任何 Event 相关(通过您的 User.eventNotified 属性),则不会检索到他/她。我还将使用 QueryBuilder 提供的 Expr 类构建 where 条件:

    $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
    

    检查QueryBuilder documentation

    【讨论】:

    • 谢谢!查看 User 实体时,您可以看到它的多对多自引用。用户有自己的朋友。如何在用户的朋友中进行完全相同的搜索?
    • 看来我的解决方案回答了这个问题。您发布了一个完全不同的 question 复制和粘贴它。你为什么不接受?顺便说一下,用 friends 属性做一个 leftJoin (为了不丢失没有朋友但匹配 where 子句的用户) .之后对左连接实体执行 innerJoin
    • 谢谢,我会试试的。我仍在测试您的解决方案并解决这个新的..,但我并没有真正理解您的第二个解决方案(我不需要保留不是朋友的用户,我试图限制从 Doctrine 返回的内容尽可能(为了表演,不想拉到很多不必要的数据))。我不太擅长加入表。不应该是“选择满足这些条件的用户,该用户的朋友”之类的,你能给我举个例子吗?非常感谢
    • 实际上,我无法让您的解决方案正常工作,我收到了Fatal error: Uncaught exception 'Doctrine\ORM\Query\QueryException' with message 'SELECT USER, * FROM Entity\User USER WHERE USER.latitude &gt; :minLat AND USER.latitude &lt; :maxLat AND USER.longitude &gt; :minLng AND USER.longitude &lt; :maxLng AND USER.available = 1 ORDER BY a.latitude - :lat + a.longitude - :lng' in /Sites....
    • 我已经更新了查询,select 函数中有一个错误,一个不需要的 '' 参数。关于我的查询,这可能是问题所在,您应该查看此question 关于您计算出的 orderBy 表达式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 2020-09-14
    • 2013-05-10
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    相关资源
    最近更新 更多