[英]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); 有一些Email
的User
(一次不止一个); Email
that belongs to Domain
s (if email@example.com, then I have the Domain
"example.com` in the database) 每个属于Domain
的Email
(如果是email@example.com,则我在数据库中拥有“ example.com” Domain
) 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
具有与Domain
的Email
,则我决定User
可以访问Profile
。
So, if the User
has an Email
email@example.com, (s)he can access the Profile
of the Domain
example.com. 因此,如果User
有Email
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查询将多次返回同一配置文件条目,但是如果您使用getResult
或getArrayResult
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
加入emails
, domain
和profile
,以便能够访问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
类添加一个方法来抓取User
的emails
并检索相应的配置文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.