簡體   English   中英

如何查詢多對一關系的反面?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM