Когда использовать innerJoin вместо where с Doctrine 2?

У меня есть сущность пользователя и сущность события. Пользователи могут уведомить о том, что хотят перейти на какие-то мероприятия. У этих пользователей также есть друзья, которые сами являются пользователями (ссылаясь на отношение многие ко многим).

Я хочу получить из своей базы данных друзей пользователя, которые удовлетворяют следующим условиям: они хотят пойти на то же мероприятие. они рядом друг с другом.

Хотя со вторым условием все в порядке, я пытаюсь создать наилучший запрос, чтобы убедиться, что первое условие соблюдается.

Вот что я сделал до сих пор:

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

К сожалению для меня, это не то, что я собираюсь делать. И мне интересно, почему. Поэтому, когда я выбираю ДРУЗЬЯ, я в основном хочу выбирать ТОЛЬКО друзей, которые уведомили, что они хотят пойти на те же мероприятия, что и те, о которых я уведомил.

Итак, я делаю innerJoin, чтобы проверить, уведомили ли друзья (они также являются пользователями), что они хотят перейти на мероприятия. И затем среди этих друзей я хочу выбрать ТОЛЬКО тех, кто собирается на те же мероприятия, что и мой $qb->expr()->eq('FRIENDS.eventNotified.id', 'USER.eventNotified.id').

Я думаю, что это моя проблема ... поскольку eventNotified - это коллекция сущности EVENT, из которой я хочу выбрать ТОЛЬКО события, о которых мы оба уведомили, могу я просто избавиться от .id? Кроме того, у меня есть ощущение, что это выбирает все события, когда я просто хочу получить уведомления о событиях, которые мы имеем в сообществе. Так что я считаю, что мне следует где-нибудь здесь сделать innerJoin, но я могу найти правильный синтаксис.

Любой совет ?

Спасибо

Бонус: следует ли мне также указать, что я хочу получить «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 WHERE USER =: user' в / Users / YohannM / Sites / meetmyfriends-back / application / libraries / Doctrine / ORM / Query / QueryException.php: 39 Трассировка стека: # 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 ...', Array) # 2 / Users / YohannM / Sites / meetmyfriends-back / application / libraries / Doctrine / ORM / Query /. Parser.php (240): Doctrine \ ORM \ Query \ Parser -> _ processDeferredPathExpressions (Object (Doctrine \ ORM \ Query \ AST \ SelectStatement)) # 3 / Users / YohannM / Sites / meetmyfriends-back / application / libraries / Doctrine / ORM / Запрос / Парс er.php (304): Doctrine \ ORM \ Query \ Parser-> getAST () # 4 / Пользователи в /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/QueryException.php on line 49

Кажется, Doctrine2 почему-то не любит 'WITH', 'USER.eventNotified = FRIENDS.eventNotified'. Я действительно не понимаю почему. без этого фрагмента кода код работает нормально, но это условие действительно не выполняется.

Большое спасибо за вашу помощь

РЕДАКТИРОВАТЬ2:

Попробовав то, что было в третьем комментарии ответа ниже, я все еще получаю аналогичное сообщение об ошибке:

Неустранимая ошибка: неперехваченное исключение «Doctrine \ ORM \ Query \ QueryException» с сообщением «ВЫБОР ПОЛЬЗОВАТЕЛЯ, ДРУЗЬЯ, СОБЫТИЕ, c, p FROM Entity \ User ПОЛЬЗОВАТЕЛЬ ВЛЕВО ПРИСОЕДИНЯЙТЕСЬ к USER.friends FRIENDS WHERE USER =: user AND USER.eventNotified = FRIENDS. eventNotified 'в /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/QueryException.php:39 Трассировка стека: # 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 ('' СОБЫТИЕ 'не ...', массив) # 2 / Users / YohannM / Sites / meetmyfriends-back / application /libraries/Doctrine/ORM/Query/Parser.php(233): Doctrine \ ORM \ Query \ Parser -> _ processDeferredIdentificationVariables () # 3 / Users / YohannM / Sites / meetmyfriends-back / application / libraries / Doctrine / ORM / Query /Parser.php(304): Доктрина \ OR M \ 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;

person Miles M.    schedule 11.02.2014    source источник
comment
Что не так с вашими результатами? Может быть, использовать innerJoin для друзей?   -  person Gohn67    schedule 11.02.2014
comment
Я не знаю, где подружиться с другом. Я получаю неверный набор результатов ..   -  person Miles M.    schedule 11.02.2014
comment
Может быть, поменять это ->leftJoin('USER.friends', 'FRIENDS') на ->innerJoin('USER.friends', 'FRIENDS')?   -  person Gohn67    schedule 11.02.2014
comment
хм, нет, потому что он будет выбирать только тех пользователей, у которых есть друзья, но у каждого пользователя есть друзья, и я уже указываю, где User.id = userid   -  person Miles M.    schedule 11.02.2014
comment
В этом есть смысл. Так вы получаете пользователей, которые совсем не совпадают, или вы получаете повторяющиеся результаты? Также, возможно, разместите соответствующие части вашей схемы. Это может быть полезно другим.   -  person Gohn67    schedule 11.02.2014
comment
буду делать, я пробую разные вещи, буду обновлять свои исследования   -  person Miles M.    schedule 13.02.2014


Ответы (1)


Несколько идей:

Вы можете попробовать использовать что-то вроде $qb->expr()->eq('FRIENDS.eventNotified', 'USER.eventNotified') вместо $qb->expr()->eq('FRIENDS.eventNotified.id', 'USER.eventNotified.id'), потому что я полагаю, что eventNotified каким-то образом является объектом, связанным с USER, имя атрибута в вашем объекте USER - eventNotified.

Во всяком случае, я бы напрямую использовал "with" в соединении, поэтому вы ограничиваете свои результаты соединения независимо от вашего предложения where:

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

Бонус: следует ли мне также указать, что я хочу получить «c» и «p» в операторе SELECT? Ответ: да, если вы хотите получить их своими геттерами после без нового запроса к базе данных

person jdharandas    schedule 11.02.2014
comment
очень полезно, позвольте мне попробовать это :) - person Miles M.; 13.02.2014
comment
Я пробовал ваше решение, которое мне кажется именно тем, что мне нужно, но я не могу обойти сообщение об ошибке, которое вы видите в моем редактировании. - person Miles M.; 14.02.2014
comment
Он может не работать с динамическими (не фиксированными значениями) или с ассоциациями, ссылающимися на себя, я не могу быть уверен, не проверив его или не проведя более глубокого исследования. Не могли бы вы попробовать это, и если у вас есть ошибки, напишите здесь свои журналы apache / ваши исключения? : $qb->select( 'USER', 'FRIENDS' ) ->from( 'Entity\User', 'USER' ) ->where( 'USER = :user' ) ->leftJoin('USER.friends', 'FRIENDS') ->andWhere('USER.eventNotified = FRIENDS.eventNotified') Не могли бы вы также написать основы ваших сущностей? То есть затронутые атрибуты: eventNotified, friends ... - person jdharandas; 14.02.2014
comment
просто попробовал, безуспешно. Я думаю, что вы правы, и мне, возможно, следует проверить это условие с помощью PHP ... Теперь, когда я знаю, в чем проблема, я думаю, может быть, мне следует создать более конкретный пост об этой проблеме (динамический WITH и doctrine2. .?) - person Miles M.; 15.02.2014
comment
Я думаю, вам следует сначала пересмотреть свои сущности и ассоциации внутри них. Использование with или where должно быть таким же, я предложил его только потому, что он более читабельный. Итак: какая у вас связь между User и EventNotified? Если oneToMany, попробуйте: $qb->select( 'USER', 'FRIENDS' ) ->from( 'Entity\User', 'USER' ) ->where( 'USER = :user' ) ->leftJoin ('User.eventNotified', 'UserEvent' ) ->leftJoin('USER.friends', 'FRIENDS') ->leftJoin ('FRIENDS.eventNotified', 'FriendsEvevnt') ->andWhere('UserEvent.id = FriendEvent.id') - person jdharandas; 15.02.2014
comment
В любом случае, как я уже сказал, вам будет легче помочь, если вы дадите мне больше информации о своих сущностях (сейчас я работаю с вами вслепую). Если у вас есть ошибки в журналах Apache, опубликуйте их тоже. Если у вас есть исключение, опубликуйте его. ;) - person jdharandas; 15.02.2014
comment
Я разместил свои объекты, как вы просили (см. "Правка"), и все сообщение об ошибке находится прямо над ним. - person Miles M.; 18.02.2014
comment
Можете ли вы попробовать запрос, который я написал вам в моем последнем комментарии здесь, и ошибку вывода для этого? Я вижу, что ваши отношения между User и eventNotified - manyToMany, поэтому обязательно иметь соединения с eventNotified как для пользователя, так и для друга. За исключением, которое вы описали в edit2, у вас их нет. - person jdharandas; 18.02.2014