Late Binding and Lazy Loading
Lazy Loading vs Eager Loading
By default, Objectiphy will eager load one-to-one and many-to-one relationships (using joins in the SQL), and lazy load one-to-many and many-to-many relationships. If your entities have Doctrine annotations, the Doctrine default will be implemented - so your one-to-one relationships can be lazy loaded even if you have not explicitly specified lazy loading.
If lazy loading, Objectiphy will return a proxy object which extends the entity you asked for. The lazy loaded property will be unset, and any attempt to access that property will trigger a magic __get
method which will cause a closure to be executed to load the child object. If you want to know whether a lazy-loading property has been loaded or not, without triggering the load if it hasn't, you can use the isChildAsleep
method on the proxy object, which will return true if the child property has not yet been loaded (note: proxy objects implement EntityProxyInterface
, so you can check if you have a proxy or an original entity using instanceof
).
You can change the default lazy or eager loading policy using a configuration option. To override the policy for a particular query, you can specify a mapping override.
Late Binding and Custom Repositories
Regardless of whether you use lazy loading or not, all one-to-many and many-to-many relationships are late bound - that is, a separate call is made to the database to load the child objects (they are not loaded using joins in the main query, because that would cause all records for the parent entity to be duplicated for every child row). A late bound, eager loaded relationship is loaded immediately, but using a separate database call. A lazy loaded relationship also uses a separate database call (ie. is always late bound), but doesn't get executed until you try to access the property (Objectiphy gives you a proxy object which extends the entity and intercepts requests for a property, executing a closure which performs the additional database query).
If you want to use a particular custom repository for an entity, you can do one of two things:
Use the
repositoryClassName
attribute of the@Table
annotation to specify the fully qualified class name of the custom repository.Override the mapping for the
@Table
annotation to specify a repository class name if it is not specified on the entity.
Where a custom repository has been specified for an entity (eg. using the @Table
annotation), Objectiphy will defer to that custom repository class every time it tries to load an entity of that type. However, if the entity is loaded via a join (due to an eager loaded one-to-one or many-to-one relationship), the parent entity's repository will be used. If you want to ensure that your custom repository is used even for eager loaded one-to-one and many-to-one relationships, you can set the alwaysLateBind
attribute to true. If you do this though, a separate database call has to be made using a new instance of the custom repository, so performance will suffer.
If you request an iterable result, Objectiphy will not late bind any properties, because that would result in nested queries which cause MySQL to crash. In that case, it will try to eager load -to-one relationships, or if recursion is detected, it will simply return null for the property. This should not cause a problem because you would typically only request an iterable result if exporting lots of flat records (for example to a CSV file), and in those cases you do not typically need a nested object hierarchy with fully resolvable recursion.
Last updated