【问题标题】:When to use innerJoin instead of where with Doctrine 2?何时使用innerJoin 而不是使用Doctrine 2?
【发布时间】:2014-03-08 18:07:49
【问题描述】:

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

我希望从我的数据库中检索满足以下条件的用户朋友: 他们想参加同一个活动。 它们彼此靠近。

虽然第二个条件很好,但我正在尝试构建可能的最佳查询,以确保遵守第一个条件。

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

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

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

所以我正在做一个 innerJoin 来检查朋友(他们也是用户)是否通知他们想要参加活动。然后在那些朋友中,我只想选择那些与我$qb->expr()->eq('FRIENDS.eventNotified.id', 'USER.eventNotified.id')参加相同活动的人。

我认为这是我的问题......因为 eventNotified 是 EVENT 实体的集合,我希望只选择我们都通知的事件,我可以摆脱 .id 吗?另外,当我只想检索我们在社区中通知的事件时,我感觉这是在选择所有事件。所以我相信我应该在这里的某个地方做一个 innerJoin 但我可以找到正确的合成器。

有什么建议吗?

谢谢

奖励:我是否还应该在 SELECT 语句中指定要检索“c”和“p”?

编辑:

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

我尝试过的代码:

//我们只想返回附近有空的用户或者谁 $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 与 USER.eventNotified 的朋友 = FRIENDS.eventNotified WHERE USER = :user' 在 /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): Doctrine\ORM\Query\Parser->_processDeferredPathExpressions(Object(Doctrine\ORM\Query\AST\SelectStatement))#3 /Users/YohannM/Sites/meetmyfriends-back/application/libraries/Doctrine/ORM/Query/Parser.php(304): Doctrine\ORM\Query\Parser->getAST()#4 /Users in /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' is not ...', 数组)#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): 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;

【问题讨论】:

  • 您的结果有什么问题?也许对朋友使用 innerJoin?
  • 我不知道把innerjoin放在朋友的哪里。我没有检索到正确的结果集..
  • 也许把这个->leftJoin('USER.friends', 'FRIENDS')改成->innerJoin('USER.friends', 'FRIENDS')
  • hmm 不,因为它只会选择有朋友的用户,但每个用户都有朋友,我已经指定了哪里 User.id = userid
  • 这是有道理的。那么您是否获得了根本不匹配的用户,或者您是否获得了重复的结果?也可以发布架构的相关部分。这可能对其他人有帮助。

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


【解决方案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

奖励:我是否还应该在 SELECT 语句中指定我想要检索 'c' 和 'p' ? 答案:是的,如果您想在没有对数据库进行新查询的情况下使用 getter 检索它们

【讨论】:

  • 很有帮助,让我试试这个:)
  • 我已经尝试过您的解决方案,这似乎是我需要的,但我无法绕过您在我的编辑中看到的错误消息..
  • 它可能不适用于动态“with”(非固定值)或自引用关联,如果不对其进行测试或进行更深入的研究,我无法确定。你可以试试这个,如果你有一些错误,在这里写下你的 apache 日志/你的异常? :$qb->select( 'USER', 'FRIENDS' ) ->from( 'Entity\User', 'USER' ) ->where( 'USER = :user' ) ->leftJoin('USER.friends', 'FRIENDS') ->andWhere('USER.eventNotified = FRIENDS.eventNotified') 你能不能也写下你的实体的基础知识?也就是受影响的属性:eventNotified、friends...
  • 刚刚试了一下,没有成功。我认为你是对的,我应该用 PHP 来验证这个条件。现在我知道问题出在哪里,我想也许我应该创建一个关于这个问题的更具体的帖子(动态 WITH 和教义 2 。 . ?)
  • 无论如何,正如我告诉你的那样,如果你给我更多关于你的实体的信息,帮助你会更容易(现在我正在盲目地与你合作)。如果您的 Apache 日志中有一些错误,也请发布它们。如果您遇到异常,请发布。 ;)
猜你喜欢
  • 2016-07-18
  • 2018-09-28
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多