[英]How to query the inverse side of a ManyToOne relationship?
長話短說:每個Organization
都可以與(可以擁有)許多User
對象相關,並且每個User
都與(擁有)一個Organization
相關。
每個用戶可以屬於一個組織,每個組織可以有多個用戶。 所以這是教科書ManyToOne。
到目前為止,一切都很好。 我將我的課程設置如下(我將省略不相關的部分):
用戶 class :
// User.php
/** @ORM\Entity */
class User implements UserInterface
{
/**
* @ORM\ManyToOne(targetEntity=Organization::class, inversedBy="user")
* @ORM\JoinColumn(name="organization_id", referencedColumnName="id", nullable=false)
*/
private $organization;
public function getOrganization(): ?Organization
{
return $this->organization;
}
public function setOrganization(?Organization $organization): self
{
$this->organization = $organization;
return $this;
}
}
組織 class :
/** @ORM\Entity */
class Organization
{
/**
* @ORM\OneToMany(targetEntity=User::class, mappedBy="organization")
*/
private $user;
public function __construct()
{
$this->user = new ArrayCollection();
}
/**
* @return Collection|User[]
*/
public function getUser(): Collection
{
return $this->user;
}
}
在組織存儲庫中,我使用 doctrine 設置了一個簡單的查詢,以獲取用戶所屬的所有組織(最多應為 1):
class OrganizationRepository extends ServiceEntityRepository
{
private $security;
public function __construct(ManagerRegistry $registry, Security $security)
{
$this->security = $security;
parent::__construct($registry, Organization::class);
}
public function selectAllFromUser()
{
return $this->createQueryBuilder('o')
->andWhere('o.user = :user')
// ->where('o.user = :user') tried with this too
->setParameter('user', $this->security->getUser())
->getQuery()
->getResult()
;
}
這給了我以下錯誤:
[語義錯誤] 第 0 行,第 48 列“用戶 =:用戶”附近:錯誤:無效的路徑表達式。 需要 StateFieldPathExpression 或 SingleValuedAssociationField。
誠然,組織上沒有 FK,所以從 SQL 的角度來看,發出錯誤是正常的。 但在紙面上,這是我想要的關系。
那么我在這里做錯了什么?
我也可以將一對多、單向與 Join Table一起使用,但此時使用 ManyToMany 並通過代碼強制執行 ManyToOne 會更容易。
首先,你把事情復雜化了。
您根本不需要通過存儲庫 go 或創建查詢生成器。
如果您想從用戶那里獲取組織,只需使用您的域並獲取組織。
$organization = $user->getOrganization();
if (!$organization instanceof Organization) {
// it appears this user was organizationless, which I would assume
// is an error condition for your application, but since you typed
// $organiza as nullable, it's possible and should be checked against
}
到了,你就完成了。 無論您要在哪里注入OrganizationRepository
,只需注入Security
或您用來獲取用戶的任何方法/服務,並直接獲取其組織。
其次,你有一個命名問題。 屬性user
應該稱為users
。 您可能認為這是一件小事,但它是一個集合,並且擁有一個暗示它包含一個簡單實體的變量名並沒有真正的意義。
如果你真的想讓查詢工作(同樣,不需要這樣做,因為你可以簡單地從用戶那里獲取組織),正確的命名會讓你意識到你所做的比較沒有多大意義. 如果您將其命名為Organization::users
,您會很清楚您所做的事情並沒有真正的意義:
->andWhere('o.users = :user')
當看到這一點時,您可能已經意識到您正在嘗試將集合與單一實體進行比較。 不合邏輯。
對於正確的查詢,您需要進行不同的比較,並確保用戶在屬於組織的用戶集合中。 為此,您使用MEMBER OF
。
例如,像這樣:
public function getOrganizationByUser(User $user): Organization
{
$organization = $this->createQueryBuilder('o')
->andWhere(':user MEMBER OF o.users')
->setParameter('user', $user)
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
if ($organization instanceof Organization) {
return $organization;
}
throw new \InvalidArgumentException('User without Organization');
}
嘗試這個..
$this->createQueryBuilder()
->select('o, u')
->from(Organization::class)
->join(User::class, 'u')
->where('u = :user')
->setParameter('user', $this-security->getUser()->getId());// i'm not sure if ->getId() is necessary...
要不就
$this->findBy(['user' => $this-security->getUser()]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.