Reputation: 115
I have two entities linked by a one-to-many unidirectional with join table association.
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;
// [...]
}
I'd like to create a method into my BarRepository
class using the a foo id and a bar id which return one or null Bar
object.
Actually my class looks like this:
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();
}
}
But this always returns a bar object even if the bar id is not associated to the foo object.
Upvotes: 3
Views: 4542
Reputation: 115
OK, thanks to staskrak, I rewrite my "query" like this, and it works fine.
The Foo
and Bar
entities are the same.
I kept the same base of the query but added an inner join between the Foo->bars
property and the Bar
entity.
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();
}
}
Upvotes: 2
Reputation: 863
First of all! It's not the required but I suggest you always write the full mapping in annotations.
Let's look at you entities. We can make the next assertion about your One-To-Many:
One Foo objects can have many Bar objects, but every Bar object refer to only one and no more Foo object. For example One person can have a lot of credit cards, but every credit card belongs to one single person.
Therefore we can write down:
/**
* @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();
}
Of course you always will have a bar object with id you have typed.
Why? Let's look at your relations(tables).
Foo - this is a table, which has field id.
Bar - this is a table, which has field id.
foo_bar_table - this table has foo_id, bar_id.
When you make the join - you just add to the one table another one.
These tables don't have association between each other. So you wanted
the Bar object - you got it.
You need to get the Bar object from the Bar repository. It will be
better.
Upvotes: 1