[question] Association partial id retrieval/hydratation #5295

Closed
opened 2026-01-22 15:03:46 +01:00 by admin · 7 comments
Owner

Originally created by @soyuka on GitHub (Oct 18, 2016).

Hi,

I was wondering how (and if it is possible) to retrieve an identity of a foreign entity, without joining it. I mean, we already know the foreign entity identifier if it is in a relation table and it might return a Proxy object with identifiers only no?

Note, I'm using HINT_FORCE_PARTIAL_LOAD because of #2094

I tried those to retrieve an identity through partial selection:

  1. SELECT PARTIAL alias.{id, field, association} because association is not in fieldMapping it will be removed by the SqlWalker.
  2. SELECT PARTIAL alias.{id, field}, IDENTITY(alias.association) this works, but the field won't be hydrated. Is there a reason why hydratation doesn't work through IDENTITY?

I think the second example may work by tweaking the resultSetMapping so that hydratation works, but I didn't try yet.

Note, that this may work the same for associations, for example:

SELECT PARTIAL alias.{id, field, association}, PARTIAL related.{id, field, association}
FROM \Entity\Foo alias
JOIN alias.association as related

Here, the expected result would be an object:

\Entity\Foo {
  id: 1,
  field: 'foo',
  association (\Entity\Bar): { //this has been joined
    id: 1,
    field: 'bar',
    association (\Proxy\Entity\FooBarRelated): { 
      //this has not been joined but we know this identifier fro the \Entity\Bar table
      id: 1
    }
  }
}

Could this be implemented? Is this a bad idea (why?)?

Originally created by @soyuka on GitHub (Oct 18, 2016). Hi, I was wondering how (and if it is possible) to retrieve an identity of a foreign entity, without joining it. I mean, we already know the foreign entity identifier if it is in a relation table and it might return a `Proxy` object with identifiers only no? Note, I'm using `HINT_FORCE_PARTIAL_LOAD` because of #2094 I tried those to retrieve an identity through partial selection: 1. `SELECT PARTIAL alias.{id, field, association}` because `association` is not in `fieldMapping` it will be removed by the `SqlWalker`. 2. `SELECT PARTIAL alias.{id, field}, IDENTITY(alias.association)` this works, but the field won't be hydrated. Is there a reason why hydratation doesn't work through `IDENTITY`? I think the second example may work by tweaking the `resultSetMapping` so that hydratation works, but I didn't try yet. Note, that this may work the same for associations, for example: ``` SELECT PARTIAL alias.{id, field, association}, PARTIAL related.{id, field, association} FROM \Entity\Foo alias JOIN alias.association as related ``` Here, the expected result would be an object: ``` \Entity\Foo { id: 1, field: 'foo', association (\Entity\Bar): { //this has been joined id: 1, field: 'bar', association (\Proxy\Entity\FooBarRelated): { //this has not been joined but we know this identifier fro the \Entity\Bar table id: 1 } } } ``` Could this be implemented? Is this a bad idea (why?)?
admin closed this issue 2026-01-22 15:03:46 +01:00
Author
Owner

@coudenysj commented on GitHub (Oct 18, 2016):

If you just fetch the \Entity\Foo object, the association field will contain an \Entity\Bar proxy object (not initialised). If you then call getField() on the association object, the data will be fetched (lazy loading), but if you call getId() on the association object, no lazy loading will occur, because the id is already know.

Does this answers your question?

@coudenysj commented on GitHub (Oct 18, 2016): If you just fetch the \Entity\Foo object, the association field will contain an \Entity\Bar proxy object (not initialised). If you then call getField() on the association object, the data will be fetched (lazy loading), but if you call getId() on the association object, no lazy loading will occur, because the id is already know. Does this answers your question?
Author
Owner

@soyuka commented on GitHub (Oct 18, 2016):

Thanks I need to try this and will get back to you!
On Tue, 18 Oct 2016 at 19:59, Jachim Coudenys notifications@github.com
wrote:

If you just fetch the \Entity\Foo object, the association field will
contain an \Entity\Bar proxy object (not initialised). If you then call
getField() on the association object, the data will be fetched (lazy
loading), but if you call getId() on the association object, no lazy
loading will occur, because the id is already know.

Does this answers your question?


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/doctrine/doctrine2/issues/6090#issuecomment-254588390,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABQr86yaxhQ-6OAeAp-6mUsyqbYmI_x4ks5q1QjvgaJpZM4KZ6Xi
.

@soyuka commented on GitHub (Oct 18, 2016): Thanks I need to try this and will get back to you! On Tue, 18 Oct 2016 at 19:59, Jachim Coudenys notifications@github.com wrote: > If you just fetch the \Entity\Foo object, the association field will > contain an \Entity\Bar proxy object (not initialised). If you then call > getField() on the association object, the data will be fetched (lazy > loading), but if you call getId() on the association object, no lazy > loading will occur, because the id is already know. > > Does this answers your question? > > — > You are receiving this because you authored the thread. > Reply to this email directly, view it on GitHub > https://github.com/doctrine/doctrine2/issues/6090#issuecomment-254588390, > or mute the thread > https://github.com/notifications/unsubscribe-auth/ABQr86yaxhQ-6OAeAp-6mUsyqbYmI_x4ks5q1QjvgaJpZM4KZ6Xi > .
Author
Owner

@soyuka commented on GitHub (Oct 19, 2016):

@coudenysj So, getting those identifiers would work if the initial query was getting back association identifiers. When using partial, because of #2094 you have to use HINT_FORCE_PARTIAL_LOAD to avoid lazy joins. Because of this, every columns you select that is an association will be removed from the query string.

For example:

$query = $queryBuilder->select('s.{id, foo, association}')->from('Entity\Foo')->getQuery();

// sql is SELECT s.id, s.foo, s.association from foo_table

$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);

// sql is SELECT s.id, s.foo from foo_table

This means that associations are null and you can not call the getId on them.

Note that if you join the association, it'll work but will do an extra join if you don't need it.

IMO it has to do with this but I'm not sure if this can easily be fixed.

@soyuka commented on GitHub (Oct 19, 2016): @coudenysj So, getting those identifiers would work if the initial query was getting back association identifiers. When using `partial`, because of #2094 you have to use `HINT_FORCE_PARTIAL_LOAD` to avoid lazy joins. Because of this, every columns you select that is an association will be removed from the query string. For example: ``` $query = $queryBuilder->select('s.{id, foo, association}')->from('Entity\Foo')->getQuery(); // sql is SELECT s.id, s.foo, s.association from foo_table $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); // sql is SELECT s.id, s.foo from foo_table ``` This means that associations are `null` and you can not call the `getId` on them. Note that if you join the association, it'll work but will do an extra join if you don't need it. IMO it has to do with [this](https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/Query/SqlWalker.php#L709) but I'm not sure if this can easily be fixed.
Author
Owner

@soyuka commented on GitHub (Oct 19, 2016):

Narrowed it down to those both conditions.

Anyway, there must be something wrong during hydratation too because fields are still null.

@soyuka commented on GitHub (Oct 19, 2016): Narrowed it down to [those](https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/Query/SqlWalker.php#L746) [both](https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/Query/SqlWalker.php#L754) conditions. Anyway, there must be something wrong during hydratation too because fields are still null.
Author
Owner

@coudenysj commented on GitHub (Oct 19, 2016):

Why do you still use partial loading? Cant you just discard the 'select' method and load the complete object? The references will contain the proxy association objects then.

@coudenysj commented on GitHub (Oct 19, 2016): Why do you still use partial loading? Cant you just discard the 'select' method and load the complete object? The references will contain the proxy association objects then.
Author
Owner

@soyuka commented on GitHub (Oct 19, 2016):

Because I don't want my other association (which is on an EAGER fetched association) to be lazy loaded.

Here is a full example of the data structure (without getters/setters):

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Foo
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $something;

    /**
     * @ORM\ManyToMany(
     *     targetEntity="AppBundle\Entity\Bar",
     *     inversedBy="bar",
     *     fetch="EAGER",
     *     cascade={"all"}
     * )
     * @ORM\JoinTable(
     *     name="FooToBar",
     *     joinColumns={@ORM\JoinColumn(name="bar_id", referencedColumnName="id", nullable=false)},
     *     inverseJoinColumns={@ORM\JoinColumn(name="foo_bar_id", referencedColumnName="id", nullable=false)}
     * )
     */
    private $bar;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User")
     * @ORM\JoinColumn(name="createdBy", referencedColumnName="id")
     */
    private $createdBy;
}

class Bar
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Association")
     * @ORM\JoinColumn(name="association", referencedColumnName="id")
     */
    private $association;
}

What I'm trying to get is:

SELECT foo.*, partial bar.{id, association}
FROM AppBundle\Entity\Foo as foo
INNER JOIN AppBundle\Entity\Bar as bar

If I'm not using partial on bar it'll lazy load bar.association, which is something I don't want.

@soyuka commented on GitHub (Oct 19, 2016): Because I don't want my other association (which is on an EAGER fetched association) to be lazy loaded. Here is a full example of the data structure (without getters/setters): ``` php <?php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Foo { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\Column(type="string", nullable=true) */ private $something; /** * @ORM\ManyToMany( * targetEntity="AppBundle\Entity\Bar", * inversedBy="bar", * fetch="EAGER", * cascade={"all"} * ) * @ORM\JoinTable( * name="FooToBar", * joinColumns={@ORM\JoinColumn(name="bar_id", referencedColumnName="id", nullable=false)}, * inverseJoinColumns={@ORM\JoinColumn(name="foo_bar_id", referencedColumnName="id", nullable=false)} * ) */ private $bar; /** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User") * @ORM\JoinColumn(name="createdBy", referencedColumnName="id") */ private $createdBy; } class Bar { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Association") * @ORM\JoinColumn(name="association", referencedColumnName="id") */ private $association; } ``` What I'm trying to get is: ``` SELECT foo.*, partial bar.{id, association} FROM AppBundle\Entity\Foo as foo INNER JOIN AppBundle\Entity\Bar as bar ``` If I'm not using partial on `bar` it'll lazy load `bar.association`, which is something I don't want.
Author
Owner

@soyuka commented on GitHub (Oct 19, 2016):

Ok my bad, I missunderstood partial loading. I think I managed to get want I wanted by only calling getId! Thanks @coudenysj

@soyuka commented on GitHub (Oct 19, 2016): Ok my bad, I missunderstood partial loading. I think I managed to get want I wanted by only calling `getId`! Thanks @coudenysj
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#5295