Doctrine one-to-many UNIDIRECTIONAL find on owning side
Doctrine one-to-many UNIDIRECTIONAL find on owning side
问题定义
所以鉴于 this part 的 Doctrine 文档(以及许多其他关于双向关联和持久性问题的文章),我有一个单向的一对多关联。它介于 Club
和 Staff
成员之间。从领域逻辑来看,Club
应该 拥有 Staff
。例如,如果我使用文档存储,Staff
将是 Club
的成员。在 99.9% 的域案例中,我有一个 club
并想要一份其员工列表。
但是,我在 Doctrine 中实现这个想法时遇到了麻烦。因为在 Doctrine 中,ONE-TO-MANY 关系只有相反的一面。所以即使在概念上下面的实体定义是错误的,但我不知道更好。
实体代码
<?php
class Club
{
/**
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
public ?UuidInterface $id;
/**
* @ORM\Column(type="string", name="name")
*/
public string $name;
/**
* @ORM\OneToMany(targetEntity="Staff", mappedBy="club")
*/
public Collection $staff;
public function __construct(string $name)
{
$this->id = Uuid::uuid4();
$this->name = $name;
$this->staff = new ArrayCollection();
}
public function addStaff(Staff $staff): void
{
$this->staff->add($staff);
}
}
class Staff
{
public const ROLE_OWNER = 'owner';
/**
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
public ?UuidInterface $id;
/**
* @ORM\Column(type="string", name="user_id")
*/
public string $userId;
/**
* @ORM\Column(type="string", name="role")
*/
public string $role;
public function __construct(string $userId, string $role)
{
$this->id = Uuid::uuid4();
$this->userId = $userId;
$this->role = $role;
}
}
但真正的问题来了。我有一个用例,我想在其中为合适的员工找到俱乐部。这是一个 (ONE-)MANY-ONE 问题,需要注意的是第一个 one 不是另一个 Doctrine 实体,而是 Staff
实体的 userId
.
所以我尝试了几种方法来获得 Club
个给定的实体 userId
:
尝试失败
<?php
// 1. Naive solution, just try to use the `ObjectRepository`
// Will cause: You cannot search for the association field 'Club#staff', because it is the inverse side of an association. Find methods only work on owning side associations.
$staffers = $this->em->getRepository(Staff::class)->findBy(['userId' => $ownerId]);
$clubs = $this->em->getRepository(Club::class)->findBy(['staff' => $staffers]);
// 2. Use `QueryBuilder` naively
// Will cause: [Semantical Error] line 0, col 131 near 'staff = s.id': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected
$qb = $this->em->createQueryBuilder();
$query = $qb->select('c')
->from(Club::class, 'c')
->join(Staff::class, 's', Join::WITH, 'c.staff = s.id')
->where('s.userId = :id')
->setParameter('id', $ownerId)
->getQuery();
// 3. Use `QueryBuilder` with knowledge if actual DB columns
// Will cause: [Semantical Error] line 0, col 138 near 'club_id WHERE': Error: Class Staff has no field or association named club_id
$qb = $this->em->createQueryBuilder();
$query = $qb->select('c')
->from(Club::class, 'c')
->join(Staff::class, 's', Join::WITH, 'c.id = s.club_id')
->where('s.userId = :id')
->setParameter('id', $ownerId)
->getQuery();
// 4. Create query directly
// Will cause: [Semantical Error] line 0, col 125 near 'staff = s.id': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected
$query = $this->em->createQuery('SELECT c FROM ' . Club::class . ' c JOIN ' . Staff::class . ' s WITH c.staff = s.id WHERE s.userId = :id')->setParameter('id', $ownerId);
我在寻找什么?
Club
和Staff
之间的单向关联,让我不用担心持久化、性能、不一致性等问题。只是双向关联的所有问题。
- 或者:
- 可能对 entities/associations
进行返工
- 一种检索
Club
实体的方法,给定 staff.userId
一个有效的解决方案,但我无法解释为什么这个有效而其他的无效。
<?php
$this->em->createQueryBuilder()
->select('c')
->from(Club::class, 'c')
->innerJoin(Staff::class, 's')
->where('s.userId = :owner')
->setParameter('owner', $ownerId)
->getQuery()
->getResult();
问题定义
所以鉴于 this part 的 Doctrine 文档(以及许多其他关于双向关联和持久性问题的文章),我有一个单向的一对多关联。它介于 Club
和 Staff
成员之间。从领域逻辑来看,Club
应该 拥有 Staff
。例如,如果我使用文档存储,Staff
将是 Club
的成员。在 99.9% 的域案例中,我有一个 club
并想要一份其员工列表。
但是,我在 Doctrine 中实现这个想法时遇到了麻烦。因为在 Doctrine 中,ONE-TO-MANY 关系只有相反的一面。所以即使在概念上下面的实体定义是错误的,但我不知道更好。
实体代码
<?php
class Club
{
/**
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
public ?UuidInterface $id;
/**
* @ORM\Column(type="string", name="name")
*/
public string $name;
/**
* @ORM\OneToMany(targetEntity="Staff", mappedBy="club")
*/
public Collection $staff;
public function __construct(string $name)
{
$this->id = Uuid::uuid4();
$this->name = $name;
$this->staff = new ArrayCollection();
}
public function addStaff(Staff $staff): void
{
$this->staff->add($staff);
}
}
class Staff
{
public const ROLE_OWNER = 'owner';
/**
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
public ?UuidInterface $id;
/**
* @ORM\Column(type="string", name="user_id")
*/
public string $userId;
/**
* @ORM\Column(type="string", name="role")
*/
public string $role;
public function __construct(string $userId, string $role)
{
$this->id = Uuid::uuid4();
$this->userId = $userId;
$this->role = $role;
}
}
但真正的问题来了。我有一个用例,我想在其中为合适的员工找到俱乐部。这是一个 (ONE-)MANY-ONE 问题,需要注意的是第一个 one 不是另一个 Doctrine 实体,而是 Staff
实体的 userId
.
所以我尝试了几种方法来获得 Club
个给定的实体 userId
:
尝试失败
<?php
// 1. Naive solution, just try to use the `ObjectRepository`
// Will cause: You cannot search for the association field 'Club#staff', because it is the inverse side of an association. Find methods only work on owning side associations.
$staffers = $this->em->getRepository(Staff::class)->findBy(['userId' => $ownerId]);
$clubs = $this->em->getRepository(Club::class)->findBy(['staff' => $staffers]);
// 2. Use `QueryBuilder` naively
// Will cause: [Semantical Error] line 0, col 131 near 'staff = s.id': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected
$qb = $this->em->createQueryBuilder();
$query = $qb->select('c')
->from(Club::class, 'c')
->join(Staff::class, 's', Join::WITH, 'c.staff = s.id')
->where('s.userId = :id')
->setParameter('id', $ownerId)
->getQuery();
// 3. Use `QueryBuilder` with knowledge if actual DB columns
// Will cause: [Semantical Error] line 0, col 138 near 'club_id WHERE': Error: Class Staff has no field or association named club_id
$qb = $this->em->createQueryBuilder();
$query = $qb->select('c')
->from(Club::class, 'c')
->join(Staff::class, 's', Join::WITH, 'c.id = s.club_id')
->where('s.userId = :id')
->setParameter('id', $ownerId)
->getQuery();
// 4. Create query directly
// Will cause: [Semantical Error] line 0, col 125 near 'staff = s.id': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected
$query = $this->em->createQuery('SELECT c FROM ' . Club::class . ' c JOIN ' . Staff::class . ' s WITH c.staff = s.id WHERE s.userId = :id')->setParameter('id', $ownerId);
我在寻找什么?
Club
和Staff
之间的单向关联,让我不用担心持久化、性能、不一致性等问题。只是双向关联的所有问题。- 或者:
- 可能对 entities/associations 进行返工
- 一种检索
Club
实体的方法,给定staff.userId
一个有效的解决方案,但我无法解释为什么这个有效而其他的无效。
<?php
$this->em->createQueryBuilder()
->select('c')
->from(Club::class, 'c')
->innerJoin(Staff::class, 's')
->where('s.userId = :owner')
->setParameter('owner', $ownerId)
->getQuery()
->getResult();