简体   繁体   English

原则DQL:4个实体之间的DQL连接

[英]Doctrine DQL: DQL Join between 4 entities

So, I have this entities structure: 所以,我有这个实体结构:

  • User that has some Email s (more than one at the same time); 有一些EmailUser (一次不止一个);
  • Each Email that belongs to Domain s (if email@example.com, then I have the Domain "example.com` in the database) 每个属于DomainEmail (如果是email@example.com,则我在数据库中拥有“ example.com” Domain
  • Each Domain MAY have a Profile linked to it. 每个Domain可以有一个链接到它的Profile

Now, given a User I'd like to get all the Profiles (s)he can access (IF ANY! Maybe the Domain doesn't have a Profile ). 现在,给定一个User我想获得他可以访问的所有Profiles (如果有的话!也许该Domain没有Profile )。

The Entities structure: 实体结构:

// User entity
use FOS\UserBundle\Model\User as BaseUser;

/**
 * @ORM\Entity
 * @ORM\Table(name="users")
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Email", mappedBy="forUser")
     */
    protected $emails;

    ...
}


// Email entity
/**
 * @ORM\Entity(repositoryClass="\AppBundle\Repository\EmailRepository")
 * @ORM\Table(name="emails")
 */
class Email
{
    /**
     * @var EmailValue
     *
     * @ORM\Id
     * @ORM\Column(name="email", type="email", nullable=false, unique=true)
     */
    protected $email;

    /**
     * @var Domain
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Domain", inversedBy="emails")
     * @ORM\JoinColumn(name="domain", referencedColumnName="second_level")
     */
    protected $domain;

    /**
     * @var \MyNamespace\Bundle\UserBundle\Entity\User
     *
     * @ORM\ManyToOne(targetEntity="MyNamespace\Bundle\UserBundle\Entity\User", inversedBy="emails")
     * @ORM\JoinColumn(name="for_user", referencedColumnName="id")
     */
    protected $forUser;

    ...
}


// Domain entity
/**
 * @ORM\Entity(repositoryClass="\AppBundle\Repository\DomainRepository")
 * @ORM\Table(name="domains")
 */
class Domain
{
    /**
     * @var string
     *
     * @ORM\Id
     * @ORM\Column(type="string", nullable=false, unique=true)
     */
    private $secondLevel;

    /**
     * @var UrlValue
     *
     * @ORM\Column(name="url", type="uri", nullable=false, unique=true)
     */
    private $url;

    ...

    /**
     * Each Domain can be linked to only one Profile.
     *
     * @var Profile|null
     *
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\Profile", inversedBy="domain")
     */
    private $profile;

    /**
     * Each Domain can have more than one Email.
     *
     * @var Collection
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Email", mappedBy="domain")
     */
    private $emails;

    ...
}


// Profile entity
/**
 * @ORM\Table(name="profiles")
 * @ORM\Entity(repositoryClass="\AppBundle\Repository\ProfileRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Profile
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="string", unique=true)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="AppBundle\Doctrine\IdGenerator")
     */
    private $id;

    /**
     * Each Store can have only one Domain.
     *
     * @var Domain
     *
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\Domain", mappedBy="profile")
     */
    private $domain;

    ...
}

Now, given a User I'd like to get all the Profiles (s)he can access (IF ANY! Maybe the Domain doesn't have a Profile ). 现在,给定一个User我想获得他可以访问的所有Profiles (如果有的话!也许该Domain没有Profile )。

I decide if a User can access a Profile if (s)he has an Email with the Domain . 如果User具有与DomainEmail ,则我决定User可以访问Profile

So, if the User has an Email email@example.com, (s)he can access the Profile of the Domain example.com. 因此,如果UserEmail email@example.com,则他可以访问Domain example.com的Profile

I know I need to join the four tables but I have no idea of how I can do such JOIN . 我知道我需要加入四个表,但是我不知道如何进行这种JOIN

Can you help me? 你能帮助我吗?

Since you made all your relations bidirectionals, you can perform such a query by joining tables from the Profile one. 由于所有关系都是双向的,因此可以通过从Profile联接表来执行这种查询。 You could use the query builder and add the following method to your ProfileRepository to perform a search based on a User instance: 您可以使用查询生成器并将以下方法添加到ProfileRepository以基于User实例执行搜索:

public function getUserProfiles(User $user)
{
    return $this->createQueryBuilder('profile')
        ->addSelect('domain') // select the corresponding domain at the same time
        ->join('profile.domain', 'domain')
        ->join('domain.emails', 'emails')
        ->where('emails.forUser = :user')
        ->setParameter('user', $user)
        ->getQuery()
        ->getResult();
}

If you simply have access to the user ID, you can use where('IDENTITY(emails.forUser) = :userId') instead of the where clause written above. 如果仅具有访问用户ID的权限,则可以使用where('IDENTITY(emails.forUser) = :userId')代替上面编写的where子句。

Note: If a user have multiple emails linked to the same domain/profile, the underlying SQL query will return the same profile entry multiple times but Doctrine will collapse them to a single entry in the result set if you use getResult or getArrayResult . 注意:如果用户有多个链接到同一域/配置文件的电子邮件,则基础SQL查询将多次返回同一配置文件条目,但是如果您使用getResultgetArrayResult Doctrine会将其折叠到结果集中的单个条目中。 You will get duplicates if you use getScalarResult as described in the documentation . 如果按照文档中所述使用getScalarResult 则将得到重复项。


You could also do this the other way around and join emails , domain and profile from User to be able to reach all the data from your User instance. 您也可以采用其他方法,并从User加入emailsdomainprofile ,以便能够访问User实例中的所有数据。 The important part would be to use leftJoin for the profile join so that domains without profiles would still get selected. 重要的部分是使用leftJoin进行profile leftJoin ,以便仍会选择没有配置文件的域。 In that case, you would need to add a method to your User class to crawl the emails of the user and retrieve the corresponding profiles. 在这种情况下,您需要向User类添加一个方法来抓取Useremails并检索相应的配置文件。

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

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