Doctrine使用连接表以一对多单向查询一个实体

时间:2017-08-04 16:50:07

标签: php symfony doctrine-orm

我有两个实体通过一对多单向链接与连接表关联。

use Doctrine\ORM\Mapping as ORM;

/**
 * @Entity(repositoryClass="FooRepository")
 */
class Foo
{
    /**
     * @var Collection
     * @ORM\ManyToMany(targetEntity="Bar")
     * @ORM\JoinTable(
     *      name="foo_bar",
     *      inverseJoinColumns={@ORM\JoinColumn(unique=true)}
     * )
     */
    private $bars;

    /**
     * @var int
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    // [...]
}
/**
 * @Entity(repositoryClass="BarRepository")
 */
class Bar
{
    /**
     * @var int
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    // [...]
}

我想在我的BarRepository类中使用a foo id和bar id创建一个方法,该方法返回一个或null Bar个对象。

实际上我的班级看起来像这样:

use Doctrine\ORM\EntityRepository;

class BarRepository extends EntityRepository
{
    /**
     * Finds a single bar.
     * @param int $fooId The foo identifier.
     * @param int $barId The bar identifier.
     * @return Bar|null
     */
    public function findOneByFoo($fooId, $barId)
    {
        $qb = $this->createQueryBuilder('b');
        $qb->innerJoin('Foo', 'f', Expr\Join::WITH, 'f.id = :fooId')
        ->where('b.id = :barId')
        ->setParameter('fooId', $fooId)
        ->setParameter('barId', $barId)
        ->getQuery()->getOneOrNullResult();
    }
}

但即使bar id与foo对象没有关联,这也会返回一个bar对象。

2 个答案:

答案 0 :(得分:1)

  1. 首先!这不是必需的,但我建议你总是写 注释中的完整映射。

    让我们来看看你的实体。我们可以就你的问题做出下一个断言 一对多的:

    一个Foo对象可以有很多Bar对象,但每个Bar对象都会引用 只有一个,没有更多的Foo对象。 例如,一个人可以拥有大量的信用卡,但每个信用卡 卡属于一个人。

  2. 因此我们可以写下来:

    /**
     * @Entity(repositoryClass="FooRepository")
     */
    class Foo
    {
         /**
          * Unidirectional One-To-Many
          * One Foo has many Bar, however Bar has only one Foo
          * 
          * @ORM\ManyToMany(targetEntity="Bar")
          * @ORM\JoinTable(
          *      name="foo_bar_table",
          *      joinColumns={@JoinColumn(name="foo_id", referencedColumnName="id")},
          *      inverseJoinColumns={@JoinColumn(name="bar_id", referencedColumnName="id", unique=true)
          */
          private $bars;
    
         /**
          * Foo constructor
          */
          public function __construct()
          {
             $this->bars = new \Doctrine\Common\Collections\ArrayCollection();
          }
    
    1. 当然,您总是会有一个已键入id的条形对象。 为什么?让我们来看看你们的关系(表格)。 Foo - 这是一个具有字段ID的表 吧 - 这是一个表,它有字段ID。 foo_bar_table - 这个表有foo_id,bar_id。

      当您进行连接时 - 您只需将另一个表添加到另一个表中。 这些表彼此之间没有关联。所以你想要 酒吧对象 - 你明白了。
      您需要从Bar存储库中获取Bar对象。这将是 更好。

答案 1 :(得分:0)

好的,感谢staskrak,我重写了我的"查询"像这样,它工作正常。 FooBar个实体是相同的。 我保留了查询的相同基础,但在Foo->bars属性和Bar实体之间添加了内部联接。

use Doctrine\ORM\EntityRepository;

class BarRepository extends EntityRepository
{
    public function findOneByFoo($fooId, $barId)
    {
        $parameters = [
            ':fooId' => $fooId,
            ':barId' => $barId
        ];
        $qb = $this->createQueryBuilder('b');
        return $qb
            ->innerJoin('Foo',    'f',  'WITH', 'f.id = :fooId')
            // below, the added inner join
            // it makes the link between the Foo->bars property and the Bar entity
            ->innerJoin('f.bars', 'fb', 'WITH', 'b.id = fb.id')
            ->where('b.id = :barId')
            ->setParameters($parameters)
            ->getQuery()
            ->getOneOrNullResult();
    }
}