Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failing inverse One-to-One relationship using a custom data type #5887

Closed
alexb-uk opened this issue Jun 20, 2016 · 4 comments
Closed

Failing inverse One-to-One relationship using a custom data type #5887

alexb-uk opened this issue Jun 20, 2016 · 4 comments
Assignees
Labels
Milestone

Comments

@alexb-uk
Copy link

Issue

The BasicEntityPersister, possibly loadOneToOneEntity() method, does not handle One-to-One relationships on the inverse side when using a custom data type.

I've stepped through the code and can see that getTypes() method is failing to find a mapping due to the SQL field name being passed in rather than the class field. E.g. from the example below its "t0.shipping_id" but I think should be "shipping". Unfortunately my understanding of the internals of Doctrine is not enough to spot the exact cause / place to fix.

Steps to reproduce

Create two classes with a one-to-one relationship using a custom data type. I used the Ramsey UUID library and Doctrine integration.

Create DQL that filters based on the inverse side and not that hydrated object returned has NULL for the relationship.

Filtering on owning side or using entityManager-find('Shipping', $id) both work correctly.

If I can give any more information or perform any tests please don't hesistate to ask.

Versions

doctrine/common v2.5.3
doctrine/dbal v2.5.4
doctrine/doctrine-module 1.0.0
doctrine/doctrine-orm-module 0.10.0
doctrine/orm v2.5.4
ramsey/uuid-doctrine 1.2.0

YAML mappings

Product:
  type: entity
  table: products
  id:
    id:
      type: uuid_binary
      generator:
        strategy: CUSTOM
      customIdGenerator:
        class: Ramsey\Uuid\Doctrine\UuidGenerator

  fields:
    name:
      type: string

  oneToOne:
      shipping:
        targetEntity: Voicesafe\Test\Shipping
        joinColumn:
          name: shipping_id
          referencedColumnName: id

Shipping:
  type: entity
  table: shipping
  id:
    id:
      type: uuid_binary
      generator:
        strategy: CUSTOM
      customIdGenerator:
        class: Ramsey\Uuid\Doctrine\UuidGenerator

  fields:
      transport:
        type: string

  oneToOne:
      product:
        targetEntity: Voicesafe\Test\Product
        mappedBy: shipping

Working Example - Owning Side

$qb = $entityManager->createQueryBuilder();

$qb->select('p')
    ->from('Product', 'p')
    ->where('p.shipping = ?1')
    ->setParameter(1, $id, 'uuid_binary');

$query  = $qb->getQuery();
$result = $query->getResult();

Debug::dump($result);

SQL Generated

SELECT p0_.id AS id_0, p0_.name AS name_1, p0_.shipping_id AS shipping_id_2 FROM products p0_ WHERE p0_.shipping_id = ')��.�GF������\"��'
SELECT t0.id AS id_1, t0.transport AS transport_2, t3.id AS id_4, t3.name AS name_5, t3.shipping_id AS shipping_id_6 FROM shipping t0 LEFT JOIN products t3 ON t3.shipping_id = t0.id WHERE t0.id = ')��.�GF������\"��'

Broken Example - Inverse side

$qb = $entityManager->createQueryBuilder();

$qb->select('s')
    ->from('Shipping', 's')
    ->where('s.id = ?1')
    ->setParameter(1, $id, 'uuid_binary');

$query  = $qb->getQuery();
$result = $query->getResult();

Debug::dump($result);

SQL Generated

SELECT s0_.id AS id_0, s0_.transport AS transport_1 FROM shipping s0_ WHERE s0_.id = ')��.�GF������\"��'
SELECT t0.id AS id_1, t0.name AS name_2, t0.shipping_id AS shipping_id_3 FROM products t0 WHERE t0.shipping_id = '2901d32e-1247-4615-9f13-baafec221604'

Note: shipping_id is using the string representation not database value.

Thanks a lot for any help / advice or even a suggested bug fix.

Alex

@liamjay
Copy link

liamjay commented Aug 16, 2016

Can someone please have a look into this bug. I would look into myself but will probably end up breaking stuff!!!

@necsord
Copy link
Contributor

necsord commented Feb 3, 2017

I came across this bug and while debugging I found following line:

BasicEntityPersister.php#L786

$identifier[$this->getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
    $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);

Keys of $identifier array are being used in BasicEntityPersister::getTypes but since the keys are in the form of table_alias.column_name e.g. t0_.user_id it can't find the appropriate type.

After changing previously mentioned line to:

$identifier[$targetClass->getFieldForColumn($targetKeyColumn)] =
    $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);

Which results in keys being in the form of mapped class field name and in BasicEntityPersister::getTypes it gets mapped correctly using target class associationMappings.

I did not test this heavily but it works for the case with which I had trouble but as I never worked with doctrine source code it would be best if someone took a look at it. I'll try creating pull request for this over the weekend but if someone wants to do it sooner feel free.

@lcobucci lcobucci self-assigned this Feb 19, 2017
@lcobucci lcobucci added the Bug label Feb 19, 2017
@lcobucci lcobucci added this to the 2.6.0 milestone Apr 30, 2017
lcobucci added a commit that referenced this issue Apr 30, 2017
…om-id-object-relationship-fix

Fixing #5887 - lazy loading of one-to-one relationship with custom id object
@lcobucci
Copy link
Member

@alexb-uk can you please check if that is fixed on master since #6274 got merged?

@Ma27
Copy link
Contributor

Ma27 commented Jan 23, 2019

I'm afraid this has implications on bidirectional one-to-one relations with multiple JoinColumns: #7579

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants