Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fetch entities without their association mapping in Doctrine 2

If you have a set of association mapped entities in Doctrine, sometimes you might want to retrieve those entities without its mapped associations being fetched and slowing the query down.

For example I have a set of entities which are association mapped in a chain of linked database tables. They are all OnetoMany associations and act as a hierarchy of prices in matrices on product pages. They can be represented as so:

SitePage->SiteMatrix->SiteItems->SiteItemPrices.

The associated mapping works perfectly, and when I use the findBy method to get the root SitePage object it contains arrays which represent the mapped entities down the chain. In other words the SitePage object contains all matrices, which contains all items which contains all prices. So far so good.

My problem is that every time I get a list of pages on my site, doctrine is walking the entire association mapping tree and returning me with the entire datatabase which is very slow. Sometime I want to just get my SitePage entity by ID and not contain all the mapped associations.

I have looked into lazy and extra lazy loading of associations but they only seem to affect certain functions, and not findBy etc. The official documentation is far from helpful: http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html

Other similar questions on Stack Overflow have gone unanswered: Doctrine 2 Association Mapping Overhead?

Is there an easy way to fetch an entity without its mapped associations? The easiest way I can see currently is to create two entities for each database table, one with association mapping and one without for use in the separate situations where they are required. It seems odd to me that you cannot simply fetch an entity and specify whether you want to link to it to other entities or fetch it by itself.

Thanks for any information on the subject.

like image 525
Asq Avatar asked Oct 30 '22 11:10

Asq


1 Answers

The JMSSerializer exclusion strategies can help you.

First, exclude all properties by default :

// ...

use JMS\Serializer\Annotation as JMS;

/**
 * @ORM\Entity
 * @JMS\ExclusionPolicy("all")
 */
class Foo

Then, choose to exclude or expose your properties :

/**
 * @ORM\Column(type="string")
 * @JMS\Expose
 */
protected $name;

Also, for your associations, you can use the MaxDepth to restrict the associated entries of your results. Example :

// Entity
/** @MaxDepth(1) */
private $selfAssociatedEntries;

// Controller
use JMS\Serializer\SerializationContext;

$serializer->serialize($data, 'json', SerializationContext::create()->enableMaxDepthChecks());

Like this, your entity will contains the $selfAssociatedEntries serialised, but the $selfAssociatedEntries doesn't have the $selfAssociationEntries property.
The serialisation is restricted to the first parent object.

Groups are a powerful feature that allows you to expose properties for some actions and exclude them for another :

/**
 * @ORM\Column(type="string", length=255, nullable=true, unique=false)
 * @JMS\Groups({"default"}) // Set the group to expose the property
 */
protected $name;

In your controller, set the group used for serialisation :

// Property 'name' is exposed
$serializer->serialize($data, 'json', SerializationContext::create()->setGroups(array('default')));

For more informations, look at Exclusion Strategies chapter of the documentation.

like image 135
chalasr Avatar answered Nov 04 '22 09:11

chalasr