何时使用内部Join而不是Doctrine 2的位置?

时间:2014-02-11 05:12:32

标签: symfony join doctrine-orm inner-join query-builder

我有一个用户实体和一个Event实体。用户可以通知他们想要参加某些活动。 这些用户也有自己的朋友(自我引用多对多关系)。

我希望从我的数据库中检索用户'满足以下条件的朋友: 他们想参加同一场比赛。 他们彼此相邻。

虽然第二个条件没问题,但我尝试建立最佳查询以确保第一个条件得到尊重。

这是我到目前为止所做的:

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


        $qb->select( 'USER', 'FRIENDS' ) // Selecting Me, the user who is asking to retrieve the users matched, and the friends who fill the criterias below
            ->from( 'Entity\User',  'USER' ) // we start with the user
            ->where( 'USER.id = :userId' ) // And I want the user the be me
            ->leftJoin('USER.friends', 'FRIENDS') // I'm going to take all of his friends
            ->innerJoin( 'FRIENDS.eventNotified', 'EVENT' ) //but ONLY the ones that have notified Events ( array collection ov EVENT entity )
            ->leftJoin( 'EVENT.categories', 'c' ) //take events category in order to avoid doing any request when getting the name of the category
            ->leftJoin( 'EVENT.place', 'p' ) // same with  the place where the event occured
            ->andWhere( 
                $qb->expr()->andX(
                    $qb->expr()->between('FRIENDS.latitude', ':minLat', ':maxLat'), //in a defined area
                    $qb->expr()->between('FRIENDS.longitude', ':minLng', ':maxLng'),
                    $qb->expr()->eq('FRIENDS.eventNotified.id', 'USER.eventNotified.id') //I want to select ONLY the friends who have notified they want to go to the same events than me (I have notified the same events as well)
                )
            )
            ->add( 'orderBy', $qb->expr()->sum( 'FRIENDS.latitude - :lat', 'FRIENDS.longitude - :lng' ) );

对我来说不幸的是,这不是我想做的事情。我想知道为什么。 因此,一旦我选择了朋友,我基本上只想选择那些已经通知他们想要参加同样事件的朋友。

因此,我正在做一个内部加入,以检查朋友(他们也是用户)是否已通知他们想要参加活动。然后在那些朋友中,我想只选择那些与我$qb->expr()->eq('FRIENDS.eventNotified.id', 'USER.eventNotified.id')发生同样事件的人。

我认为存在我的问题...因为eventNotified是EVENT实体的集合,我希望仅选择我们已经通知的事件,我可以摆脱.id吗?另外,我觉得这只是在我想要检索我们在commun中发生的事件时选择所有事件。所以我相信我应该在某处做一个内心加入,但我能找到合适的合成器。

有什么建议吗?

由于

奖金:我是否还应该指定我想要检索' c'和' p'在SELECT语句中?

编辑:

我尝试了下面的解决方案,但是我收到了这个错误,我不明白。如何检索完整的错误消息? (有些部分遗失!)

我尝试过的代码:

//我们只想返回附近可用的用户或谁         $ qb = $ this-> getEntityManager() - > createQueryBuilder();

    $qb->select( 'USER', 'FRIENDS' ) // Selecting Me, the user who is asking to retrieve the users matched, and the friends who fill the criterias below
        ->from( 'Entity\User',  'USER' ) // we start with the user
        ->where( 'USER = :user' ) // And I want the user the be me
        ->leftJoin('USER.friends', 'FRIENDS', 'WITH', 'USER.eventNotified = FRIENDS.eventNotified');

    $array = array(
         'user'   => $user
    );

    $qb->setParameters( $array );

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

错误:

  

致命错误:未捕获的异常' Doctrine \ ORM \ Query \ QueryException'   使用消息' SELECT USER,FRIENDS FROM Entity \ User USER LEFT JOIN   USER.friends FRIENDS WITH USER.eventNotified = FRIENDS.eventNotified   用户=:用户'在   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/QueryException.php:39Stack   跟踪:#0   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(429):   Doctrine \ ORM \ Query \ QueryException :: dqlError(' SELECT USER,FR ...')#1   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(686):   Doctrine \ ORM \ Query \ Parser-> semanticalError(' Invalid PathExp ...',   阵列)#2   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(240):   教义\ ORM \查询\ Parser-> _processDeferredPathExpressions(对象(学说\ ORM \查询\ AST \ SelectStatement))#3   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(304):   Doctrine \ ORM \ Query \ Parser-> getAST()#4 /用户   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/QueryException.php   第49行

由于某种原因,Doctrine2似乎不喜欢'WITH', 'USER.eventNotified = FRIENDS.eventNotified'。我真的不明白为什么。没有这些代码,代码工作正常,但这种情况确实没有实现。

非常感谢您的帮助

EDIT2:

在尝试下面答案的第三条评论后,我仍然收到类似的错误消息:

  

致命错误:未捕获的异常' Doctrine \ ORM \ Query \ QueryException'   消息' SELECT USER,FRIENDS,EVENT,c,p FROM Entity \ User USER   LEFT JOIN USER.friends FRIENDS WHERE USER =:user AND   USER.eventNotified = FRIENDS.eventNotified'在   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/QueryException.php:39Stack   跟踪:#0   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(429):   Doctrine \ ORM \ Query \ QueryException :: dqlError(' SELECT USER,FR ...')#1   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(528):   Doctrine \ ORM \ Query \ Parser-> semanticalError('' EVENT'不是......',   阵列)#2   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(233):   教义\ ORM \查询\ Parser-> _processDeferredIdentificationVariables()#3   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(304):   Doctrine \ ORM \ Query \ Parser-> getAST()#4 / Users / YohannM / Sites / meetmyfrien   在   /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/QueryException.php   第49行

我认为我们不能做动态条件。我不知道是否有办法用学说做到这一点,否则我可能不得不用PHP做到这一点我猜...

以下是我的活动和用户实体的结构:

用户实体:

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;

事件实体:

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

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=200, precision=0, scale=0, nullable=false, unique=false)
     */
    private $name;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="Entity\Category", inversedBy="events")
     * @ORM\JoinTable(name="categories_events")
     */
    private $categories;


    /**
     * @var \Entity\User
     *
     * @ORM\ManyToOne(targetEntity="Entity\User", inversedBy="events")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     **/
    private $user;


    /**
     * @var \Entity\Admin
     *
     * @ORM\ManyToOne(targetEntity="Entity\Admin", inversedBy="events")
     * @ORM\JoinColumn(name="admin_id", referencedColumnName="id")
     **/
    private $admin;

    /**
     * @var \Entity\Place
     *
     * @ORM\ManyToOne(targetEntity="Entity\Place", inversedBy="events", cascade={"persist"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $place;

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

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

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

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="date_created", type="datetime", precision=0, scale=0, nullable=false, unique=false)
     */
    private $dateCreated;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="date_start", type="datetime", precision=0, scale=0, nullable=true, unique=false)
     */
    private $dateStart;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="date_end", type="datetime", precision=0, scale=0, nullable=true, unique=false)
     */
    private $dateEnd;

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

     /**
     * Bidirectional - One-To-Many (INVERSE SIDE)
     *
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="Entity\Request", mappedBy="event")
     */
    private $invitations;

    /**
     * Bidirectional - Many users are intending many events (INVERSE SIDE)
     *
     * @ORM\ManyToMany(targetEntity="User", mappedBy="eventNotified", cascade={"persist"})
     */
    private $userNotified;

1 个答案:

答案 0 :(得分:1)

一些想法:

您可以尝试使用$qb->expr()->eq('FRIENDS.eventNotified', 'USER.eventNotified')而不是$qb->expr()->eq('FRIENDS.eventNotified.id', 'USER.eventNotified.id')之类的内容,因为我认为eventNotified是一个与用户相关的实体,您的USER实体中的属性名称是eventNotified。

无论如何,我会在联接中直接使用“with”,因此您可以独立于where子句限制联接结果:

  ->leftJoin('USER.friends', 'FRIENDS', 'WITH', 'FRIENDS.eventNotified = USER.eventNotified') // I'm going to take all of his friends

Bonus:我还应该指定我想在SELECT语句中检索'c'和'p'吗? 答:是的,如果你想在没有对数据库的新查询之后用你的getter检索它们

相关问题