Benjamin Benjamin - 4 months ago 36
PHP Question

Doctrine get full entity after a partial query

I am working on a system that is build using Zend Framework 2 and Doctrine 2.

In this system I am working on the contracts part where I want a list with some data (a partial query) from all contracts and I need to fill in a form with all data (entity find) from a specific contract.

However, since the contract to be filled in the form is also a result of the partial query, the properties that had not been loaded in the PARTIAL query will not be loaded for the queried entity either.

I have simplified the data to show only the current issue, the real entity has more fields:

Entity:


use Doctrine\ORM\Mapping as ORM;

/**
* ContractSub
*
* @ORM\Table(name="contract_sub", indexes={@ORM\Index(name="contract_id", columns={"contract_id"}), @ORM\Index(name="list_pension_start", columns={"list_pension_start_id"}), @ORM\Index(name="list_lease_car_category", columns={"list_lease_car_category_id"}), @ORM\Index(name="created_by_id", columns={"created_by_id"})})
* @ORM\Entity(repositoryClass="Application\Repository\ContractSubRepository")
* @ORM\HasLifecycleCallbacks
*/
class ContractSub
{

/**
*
* @var integer @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;

/**
*
* @var \DateTime @ORM\Column(name="start_date", type="date", nullable=false)
*/
private $startDate;

/**
*
* @var \DateTime @ORM\Column(name="end_date", type="date", nullable=true)
*/
private $endDate;

/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}

/**
* Set startDate
*
* @param \DateTime $startDate
*
* @return ContractSub
*/
public function setStartDate($startDate)
{
$this->startDate = $startDate;

return $this;
}

/**
* Get startDate
*
* @return \DateTime
*/
public function getStartDate()
{
return $this->startDate;
}

/**
* Set endDate
*
* @param \DateTime $endDate
*
* @return ContractSub
*/
public function setEndDate($endDate)
{
$this->endDate = $endDate;

return $this;
}

/**
* Get endDate
*
* @return \DateTime
*/
public function getEndDate()
{
return $this->endDate;
}
}


Repository:


use Doctrine\ORM\EntityRepository;

class ContractSubRepository extends EntityRepository
{

public function getPartialStuffForTest()
{
$oQuery = $this->_em->createQuery('SELECT PARTIAL ContractSub.{id, startDate}
FROM Application\Entity\ContractSub ContractSub');
return $oQuery->getResult();
}
}


Controller:


use Zend\Mvc\Controller\AbstractActionController;

class ContractController extends AbstractActionController
{
public function testAction()
{
$oEntityManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$aContracts = $oEntityManager->getRepository('Application\Entity\ContractSub')->getPartialStuffForTest();
$oContractSub = $oEntityManager->getRepository('Application\Entity\ContractSub')->find(38);
var_dump($oContractSub->getStartDate());
var_dump($oContractSub->getEndDate());
die();
}
}


This outputs:

object(DateTime)[479]
public 'date' => string '2015-06-01 00:00:00.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Amsterdam' (length=16)

null


Indicating that the
endDate
is not loaded, even though I do a
find
to retrieve the complete entity.
When I comment the line that executes the
getPartialStuffForTest()
, I do get the
endDate
as well.

So I was wondering if there is any way to force Doctrine to retrieve the full entity after it already has a cached version of the partial entity?

Answer

To fully load a partial you have to use $entityManager->refresh($object).

Your answer is in the first paragraph in the Doctrine2 documentation chapter 18. Partial objects.

Use of partial objects is tricky. Fields that are not retrieved from the database will not be updated by the UnitOfWork even if they get changed in your objects. You can only promote a partial object to a fully-loaded object by calling EntityManager#refresh() or a DQL query with the refresh flag.