Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-1358

Native Query hydration ignores empty entity doublons

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.1
    • Fix Version/s: 2.1.3, 2.2
    • Component/s: ORM
    • Security Level: All
    • Labels:
      None
    • Environment:
      Debian 6, Symfony 2, Doctrine 2

      Description

      My case is the follwing :

      In a range of dates, I want to know if an entity has been defined for each day. So the raw SQL result would looks like :

      DATE              ID NAME
      --------- ---------- -------------
      19-SEP-11          4 [Entity Name]
      20-SEP-11          1 [Entity Name]
      21-SEP-11          2 [Entity Name]
      22-SEP-11          3 [Entity Name]
      23-SEP-11       NULL NULL
      24-SEP-11       NULL NULL
      25-SEP-11       NULL NULL
      26-SEP-11       NULL NULL
      27-SEP-11          7 [Entity Name]
      28-SEP-11          6 [Entity Name]
      29-SEP-11          5 [Entity Name]
      
      11 rows selected.
      

      The range calculation forced me to use Native Query, but I stumbled upon a strange behavior : the Result array showed less records than the raw SQL would provide. After some dirty debugging, I found out that during hydration, an array of previously hydrated object keys was stored ObjectHydrator->_identifierMap. The key of null elements (the gap in the SQL result above) is stored too. The problem is that when there is multiple empty elements, hydration only keeps one, and forget the others, thus reducing the overall size of the output result.

      I've already come up with a quick n'dirty fix wich suits my current needs, but it would be better if this issue was addressed at a more global level.

      Here's the one-liner fix :

      Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 397 was :
                      if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]]) ) {
      
      Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 397 now :
                      if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]]) || str_replace( '|', '', $id[$dqlAlias]) == '') {
      

        Activity

        Hide
        Benjamin Eberlei added a comment -

        Doesnt he still hydrate an empty object for this row then? Why are you even using the object hydrator? I rather tend to go and throw an exception if for a query using the ObjectHydrator $id[$dqlAlias] is empty, because frankly this is just not supported.

        Show
        Benjamin Eberlei added a comment - Doesnt he still hydrate an empty object for this row then? Why are you even using the object hydrator? I rather tend to go and throw an exception if for a query using the ObjectHydrator $id [$dqlAlias] is empty, because frankly this is just not supported.
        Hide
        Benjamin Lorteau added a comment -

        He does hydrate one empty object for the first line with empty ID, but he does not hydrate further empty object.

        Thus, instead of having an array with the following objects :

         
        Entity(id=4)
        Entity(id=1)
        Entity(id=2)
        Entity(id=3)
        Entity(id=)
        Entity(id=)
        Entity(id=)
        Entity(id=)
        Entity(id=7)
        Entity(id=6)
        Entity(id=5)
        

        I got :

         
        Entity(id=4)
        Entity(id=1)
        Entity(id=2)
        Entity(id=3)
        Entity(id=)
        Entity(id=7)
        Entity(id=6)
        Entity(id=5)
        
        Show
        Benjamin Lorteau added a comment - He does hydrate one empty object for the first line with empty ID, but he does not hydrate further empty object. Thus, instead of having an array with the following objects : Entity(id=4) Entity(id=1) Entity(id=2) Entity(id=3) Entity(id=) Entity(id=) Entity(id=) Entity(id=) Entity(id=7) Entity(id=6) Entity(id=5) I got : Entity(id=4) Entity(id=1) Entity(id=2) Entity(id=3) Entity(id=) Entity(id=7) Entity(id=6) Entity(id=5)
        Hide
        Benjamin Eberlei added a comment -

        Yes, but can you show me your DQL statement?

        Show
        Benjamin Eberlei added a comment - Yes, but can you show me your DQL statement?
        Hide
        Benjamin Lorteau added a comment -

        I'm using Native Query, so I guess it's not DQL, but here's the query (Oracle SQL)

        SELECT *
        FROM (
            SELECT to_date(:date_start,\'dd-mm-yyyy\') + rownum -1 as period_date
            FROM all_objects
            WHERE rownum <= to_date(:date_end,\'dd-mm-yyyy\') - to_date(:date_start,\'dd-mm-yyyy\')+1
        )
        LEFT JOIN entity ON period_date = entity_date',
        
        Show
        Benjamin Lorteau added a comment - I'm using Native Query, so I guess it's not DQL, but here's the query (Oracle SQL) SELECT * FROM ( SELECT to_date(:date_start,\'dd-mm-yyyy\') + rownum -1 as period_date FROM all_objects WHERE rownum <= to_date(:date_end,\'dd-mm-yyyy\') - to_date(:date_start,\'dd-mm-yyyy\')+1 ) LEFT JOIN entity ON period_date = entity_date',
        Hide
        Benjamin Eberlei added a comment -

        For the Array- and ObjectHydrator the ID is a required result.

        I am not sure how to proceed with this, i think the right behavior is to return null as the object when no id is found. What do you think?

        Is the Date a scalar value of the result?

        Show
        Benjamin Eberlei added a comment - For the Array- and ObjectHydrator the ID is a required result. I am not sure how to proceed with this, i think the right behavior is to return null as the object when no id is found. What do you think? Is the Date a scalar value of the result?
        Hide
        Benjamin Lorteau added a comment - - edited

        The expected results would be, in order of preference :

        • Entity without id set (like in my example above)
        • null value

        And yes, the Date was an additional scalar value for which I needed the Native Query

        Show
        Benjamin Lorteau added a comment - - edited The expected results would be, in order of preference : Entity without id set (like in my example above) null value And yes, the Date was an additional scalar value for which I needed the Native Query
        Hide
        Benjamin Eberlei added a comment -

        Your example lacks details but, for case one. Did the queries return values for the non-id columns of this entity?

        Show
        Benjamin Eberlei added a comment - Your example lacks details but, for case one. Did the queries return values for the non-id columns of this entity?
        Hide
        Benjamin Lorteau added a comment -

        Sorry for the concision, I didn't wanted to flood my comment with unrelated data.

        The fact is the queries returned values for the non-id columns when the ID was set, and null values when not. I will update my comment.

        Show
        Benjamin Lorteau added a comment - Sorry for the concision, I didn't wanted to flood my comment with unrelated data. The fact is the queries returned values for the non-id columns when the ID was set, and null values when not. I will update my comment.
        Hide
        Benjamin Eberlei added a comment -

        I will go with adding NULL values there. This is more consistent, since null represents a non-existent entity.

        Fixed and merged back into 2.1.x

        Show
        Benjamin Eberlei added a comment - I will go with adding NULL values there. This is more consistent, since null represents a non-existent entity. Fixed and merged back into 2.1.x

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            Benjamin Lorteau
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: