Jira issue originally created by user romanb:
When fetching objects and using a result cache, it would probably be better to cache the SQL result array instead of the hydrated objects. That way, when grabbing from the cache managed entities can be returned. Also, caching is more efficient since an SQL result array does not need to be serialized/unserialized when storing in apc or memcached.
Comment created by @beberlei:
It also avoids unnecessary "proxy not initialized, can't serialize" exceptions.
Comment created by @jwage:
If we make this change, the caching won't be "as" affective right since it will still have to go through the hydration process?
Correct, but its almost impossible to result cache entities because they are not allowed to have a single proxy entity at any depth of the object graph.
Maybe we should introduce another notion of SqlResultCache? The ResultCache is good and effective for all Array and Scalar hydration modes, however the SQL Result caching is more useful for Object Hydration.
Comment created by romanb:
Exactly. Yes it means hydration is always run but you really cant speak of "effective" when caching large object result sets because serialization & especially unserialization which then happens on every request will be pretty slow.
As Benjamin said, result caching is perfect for anything but objects so this ticket really only affects queries that use object hydration. Storing the raw sql result for these has the advantage that the objects retrieved from the cache are not detached and thus need not be merged and also you dont have issues with uninitialized proxies preventing serialization.
Is this also the cause of this issue? http://www.doctrine-project.org/jira/browse/[DDC-446](http://www.doctrine-project.org/jira/browse/DDC-446)
Since we're unserializing some objects, does Doctrine know about them?
Yes, as already said, objects coming from the result cache are currently DETACHED. Thus the EM does not care about them. This is fine if you just want to display them but if you want to modify them and persist new changes, you need to merge() the ones you want to become MANAGED again into the EM.
It should also be noticed that if we make this change and the cached objects are managed after grabbing from the cache this can have a negative effect on flushing performance, if you only want the cached objects for read-only/display purposes. Maybe we should still provide both options, like Benjamin said.
Moved to 2.1 for now.
Comment created by dcousineau:
I would like to see the ability to cache pre-hydration as I have already run into this issue.
Maybe the interface could be along similar syntaxes as turning on result caches
->setResultCachePreHydration(true); //Result cache should work pre-hydration, false caches
However from my examinations the hydrators will have to be rewritten to accept an array instead of a pdo statement.
That would be my vote. If you don't have the resources to work on the ticket I can tackle it.
rewriting to use an array is not an option. this would require to call ->fetchAll() which is not wanted for the Iterate Result feature.
There has to be a better way to redefine the method signatures to allow both use-cases.
Ah btw, any help is appreciated. Just Fork doctrine2 over at Github and develop this feature in a new branch (git checkout -b DDC-217) and link it here or issue a pull request on Github.
Forked here: https://github.com/dcousineau/doctrine2 though probably should pull it out into a local branch.
I went ahead and went down that route of altering hydrators to accept an array as well as a statement. This way uncached queries will work with the statement as it used to, but can also hydrate from an array.
As for the iterable hydrator you have a point but in this case you really can't cache it period, be it pre or post hydration (since to cache we have to serialize ALL the information).
What I have up is working(ish with the caveat that I backported the changes to an earlier tagged release for our application and tested using that), take a look and see if we like or don't like how I did it.
You'll notice I did split up *doExecute() for the query objects, because the DQL query object does so much analysis in the *doExecute() method which produces and attaches information (namely the result set mapping) that is depended on by the hydration process, I split it up into a "doPreExecute" function so that it can be called separately without actually executing the query.
Yes i know that the serialize thing won't work with the Iterator. My point was that the Iterator USES the Hydrator code and it should still support that use-case.
See the IterableResult class and make sure that its still working after your refactoring.
I don't like the instanceof check then iterate vs the forach over the array. I would rather find a solutio nthat works for both, but i cant find one now that doesnt involve findAll() (which is bad).
I'll double check against the IterableResult and make sure it's compatible.
Beyond that, I don't know what I could other than the instance of check. I could extend the statement object and create a statement that takes a flat array so all the code remains the same (i'm passing a statement).
Comment created by sobstel:
I've made my own implementation for this:
There are no changes in specific hydrators and there is no fetchAll(). I've added 2 wrappers: one for cached result array, and one for uncached pdo statement. The former (CachedResultStatement) is actually ArrayIterator which just implements used methods (fetch & closeCursor => also specified in ResultStatementInterface). The latter is decorator for stmt, which just collects results on each call of fetch() (results are later available by calling getResult), and apart from this all calls are delegated to actual stmt object.
I've used (copied) following changes from Daniel dcousineau@c23b5a9
Btw, what is your reasoning for not using fetchAll() anywhere?
Comment created by hypno:
maybe a dumb question but is it normal that result cache fetched entities associations are set to blank objects?
Comment created by bogdan.albei:
I've sent a pull request for the fix(bogdanalbei@00d1aa2) . The changes were tested under live conditions sice v2.0.
Workaround for this issue: https://gist.github.com/57e6b4deea566baac053
Also: This will be fixed in 2.2.
First step of this hit DBAL today doctrine/dbal#69
DBAL code was heavily refactored and merged, the ORM PR is now open for discussion:
Merged into master
Issue was closed with resolution "Fixed"
Related Pull Request was closed: #87