EntityManager wants to persist an existing relationship value #5942

Closed
opened 2026-01-22 15:22:45 +01:00 by admin · 10 comments
Owner

Originally created by @hskrasek on GitHub (Apr 6, 2018).

So this is going to be a lot, but here is a cut down version of what I'm working with. I have three entities (technically four) at play here. Appointment, Conversion (AppointmentConversion) and Profile. Here is the setup for each entity:

/**
 * @ORM\Entity
 */
class Appointment
{
    /**
     * @var Conversion
     *
     * @ORM\ManyToOne(targetEntity="AppointmentConversion", cascade={"persist"}, inversedBy="appointment")
     * @ORM\JoinColumn(name="conversionId", referencedColumnName="id")
     */
    private $conversion;
}
/**
 * @ORM\Entity()
 */
class AppointmentConversion extends Conversion
{
    /**
     * @var Appointment
     *
     * @ORM\OneToOne(targetEntity="Appointment", mappedBy="conversion", fetch="EAGER")
     */
    private $appointment;
}
/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="conversionTypeId", type="integer")
 * @ORM\DiscriminatorMap({
 *  2 = "AppointmentConversion",
 *  1 = "Conversion"
 * })
 */
class Conversion
{
    /**
     * @var Profile
     *
     * @ORM\ManyToOne(targetEntity="Profile")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="profileId", referencedColumnName="id")
     * })
     */
    private $profile;
}
/**
 * @ORM\Entity
 */
class Profile
{
}

For what I'm trying to do, I need the appointment, the conversion, and the profile. So I'm doing the following:

public function getAppointmentForConversion(string $publicId): Appointment
    {
        return $this->getEntityManager()->createQueryBuilder()
            ->select('a, c, p')
            ->from($this->getEntityName(), 'a')
            ->join('a.conversion', 'c')
            ->join('c.profile', 'p')
            ->addCriteria(
                Criteria::create()->where(Criteria::expr()->eq('a.publicId', $publicId))
            )
            ->getQuery()
            ->getSingleResult();
    }

I use the profile object to get a value for a third party API call, but otherwise I'm only updated the Appointment and Conversion (AppointmentConversion) and persisting both entities and then at the end flushing. Whenever I call flush I get the following message:

A new entity was found through the relationship 'Conversion#profile' that was not configured to cascade persist operations for entity: Profile@000000005854d8b6000000004f05f655. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Profile#__toString()' to get a clue.

If I persist this object it tries to insert as a brand new profile when it already exists. I am fairly new to Doctrine so try as I may and xdebugging every which way, I cannot for the life of me figure out why the entity manager whats to persist the profile object when I just need to make updates to the Appointment and Conversion (AppointmentConversion)

Edit:

For more context I'm doing something like this:

$appointment = getAppointmentForConversion('someId');
$conversion = $appointment->getConversion();
$profile = $conversion->getProfile();
// At this point all three entities are rows that already exist in the database.

$this->someThirdPartyApiCall($profile); // Only need the profile to make a third party API call

$conversion->setFoo('new val');
$appointment->setBar('also new val');

$em->persist($conversion);
$em->persist($appointment);
$em->flush();
Originally created by @hskrasek on GitHub (Apr 6, 2018). So this is going to be a lot, but here is a cut down version of what I'm working with. I have three entities (technically four) at play here. Appointment, Conversion (AppointmentConversion) and Profile. Here is the setup for each entity: ```php /** * @ORM\Entity */ class Appointment { /** * @var Conversion * * @ORM\ManyToOne(targetEntity="AppointmentConversion", cascade={"persist"}, inversedBy="appointment") * @ORM\JoinColumn(name="conversionId", referencedColumnName="id") */ private $conversion; } ``` ```php /** * @ORM\Entity() */ class AppointmentConversion extends Conversion { /** * @var Appointment * * @ORM\OneToOne(targetEntity="Appointment", mappedBy="conversion", fetch="EAGER") */ private $appointment; } ``` ```php /** * @ORM\Entity * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="conversionTypeId", type="integer") * @ORM\DiscriminatorMap({ * 2 = "AppointmentConversion", * 1 = "Conversion" * }) */ class Conversion { /** * @var Profile * * @ORM\ManyToOne(targetEntity="Profile") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="profileId", referencedColumnName="id") * }) */ private $profile; } ``` ```php /** * @ORM\Entity */ class Profile { } ``` For what I'm trying to do, I need the appointment, the conversion, and the profile. So I'm doing the following: ```php public function getAppointmentForConversion(string $publicId): Appointment { return $this->getEntityManager()->createQueryBuilder() ->select('a, c, p') ->from($this->getEntityName(), 'a') ->join('a.conversion', 'c') ->join('c.profile', 'p') ->addCriteria( Criteria::create()->where(Criteria::expr()->eq('a.publicId', $publicId)) ) ->getQuery() ->getSingleResult(); } ``` I use the profile object to get a value for a third party API call, but otherwise I'm only updated the Appointment and Conversion (AppointmentConversion) and persisting both entities and then at the end flushing. Whenever I call flush I get the following message: > A new entity was found through the relationship 'Conversion#profile' that was not configured to cascade persist operations for entity: Profile@000000005854d8b6000000004f05f655. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={\"persist\"}). If you cannot find out which entity causes the problem implement 'Profile#__toString()' to get a clue. If I persist this object it tries to insert as a brand new profile when it already exists. I am fairly new to Doctrine so try as I may and xdebugging every which way, I cannot for the life of me figure out why the entity manager whats to persist the profile object when I just need to make updates to the Appointment and Conversion (AppointmentConversion) **Edit:** For more context I'm doing something like this: ```php $appointment = getAppointmentForConversion('someId'); $conversion = $appointment->getConversion(); $profile = $conversion->getProfile(); // At this point all three entities are rows that already exist in the database. $this->someThirdPartyApiCall($profile); // Only need the profile to make a third party API call $conversion->setFoo('new val'); $appointment->setBar('also new val'); $em->persist($conversion); $em->persist($appointment); $em->flush(); ```
admin closed this issue 2026-01-22 15:22:46 +01:00
Author
Owner

@zquintana commented on GitHub (Apr 7, 2018):

It's hard to see what's going on without knowing the rest of the process that is updating the object. That said, it looks like the problem you have is that the profile object you are setting on the Conversation entity isn't persisted before it's flushed. This can happen if you are creating a new Profile object and setting it on the Conversation without persisting it with the entity manager. There are a few other ways I've seen this can happen, but again those are fringe cases that without knowing more about your application would only add noise to solving the issue.

@zquintana commented on GitHub (Apr 7, 2018): It's hard to see what's going on without knowing the rest of the process that is updating the object. That said, it looks like the problem you have is that the profile object you are setting on the Conversation entity isn't persisted before it's flushed. This can happen if you are creating a new Profile object and setting it on the Conversation without persisting it with the entity manager. There are a few other ways I've seen this can happen, but again those are fringe cases that without knowing more about your application would only add noise to solving the issue.
Author
Owner

@hskrasek commented on GitHub (Apr 9, 2018):

@zquintana I updated my description with an example of what I'm roughly doing and putting it here as well. But in this case I'm not making a new profile object, the profile object already exists and is fetch joined by the DQL.

$appointment = getAppointmentForConversion('someId');
$conversion = $appointment->getConversion();
$profile = $conversion->getProfile();
// At this point all three entities are rows that already exist in the database.

$this->someThirdPartyApiCall($profile); // Only need the profile to make a third party API call

$conversion->setFoo('new val');
$appointment->setBar('also new val');

$em->persist($conversion);
$em->persist($appointment);
$em->flush();
@hskrasek commented on GitHub (Apr 9, 2018): @zquintana I updated my description with an example of what I'm roughly doing and putting it here as well. But in this case I'm not making a new profile object, the profile object already exists and is fetch joined by the DQL. ```php $appointment = getAppointmentForConversion('someId'); $conversion = $appointment->getConversion(); $profile = $conversion->getProfile(); // At this point all three entities are rows that already exist in the database. $this->someThirdPartyApiCall($profile); // Only need the profile to make a third party API call $conversion->setFoo('new val'); $appointment->setBar('also new val'); $em->persist($conversion); $em->persist($appointment); $em->flush(); ```
Author
Owner

@zquintana commented on GitHub (Apr 9, 2018):

Seems odd, by sound of the error I still think that the profile object is getting attached some how to the conversation before it is persisted. Are you using lazy getter in conversation getProfile that creates a Profile when it doesn't exist? Also have you checked the query that is just to make sure it's creating the query you're expecting? Is this in Symfony project? If it is, I'd suggest using the profiler to see the query generated and the validate the schema. You can also validate your schema with the built in doctrine tool, have you tried that to make sure everything is mapped correctly from Doctrines stand point?

@zquintana commented on GitHub (Apr 9, 2018): Seems odd, by sound of the error I still think that the profile object is getting attached some how to the conversation before it is persisted. Are you using lazy getter in conversation getProfile that creates a Profile when it doesn't exist? Also have you checked the query that is just to make sure it's creating the query you're expecting? Is this in Symfony project? If it is, I'd suggest using the profiler to see the query generated and the validate the schema. You can also validate your schema with the built in doctrine tool, have you tried that to make sure everything is mapped correctly from Doctrines stand point?
Author
Owner

@hskrasek commented on GitHub (Apr 9, 2018):

@zquintana So the project object is coming "pre-attached" to the conversion based on the following line from the above DQL:

->join('a.conversion', 'c')
->join('c.profile', 'p')

So no lazy getting, anything lazy that'd happen is if I made Doctrine use a reference proxy to lazy load the profile first. But since I'm explicitly fetch-joining it, that shouldn't be the case.

When I checked the query on Friday it was loading all the correct data (not gonna paste it cause it's a long long long select statement)

This is a Laravel project, but I have query logging enabled at the moment. When you say You can also validate your schema with the built in doctrine tool, have you tried that to make sure everything is mapped correctly from Doctrines stand point?, which tool are you referencing?

@hskrasek commented on GitHub (Apr 9, 2018): @zquintana So the project object is coming "pre-attached" to the conversion based on the following line from the above DQL: ``` ->join('a.conversion', 'c') ->join('c.profile', 'p') ``` So no lazy getting, anything lazy that'd happen is if I made Doctrine use a reference proxy to lazy load the profile first. But since I'm explicitly fetch-joining it, that shouldn't be the case. When I checked the query on Friday it was loading all the correct data (not gonna paste it cause it's a long long long select statement) This is a Laravel project, but I have query logging enabled at the moment. When you say `You can also validate your schema with the built in doctrine tool, have you tried that to make sure everything is mapped correctly from Doctrines stand point?`, which tool are you referencing?
Author
Owner

@zquintana commented on GitHub (Apr 9, 2018):

If you've setup with the laravel doctrine package you should have the artisan command doctrine:schema:validate. That's the tool that validates your mapping data with Doctrine.

I see that the join is suppose to select the profile and load it's relation, but the error you're getting implies that the profile attached to the conversation is not managed. I've used Doctrine for a while and the only times I've seen that happen is when the object is being set accidentally to the property. Generally when a query is made via the entity manager any mapped entities are added to the unit of work right after they're mapped to entities. So if you're getting that error and the you are receiving an entity, it's likely that another process you have in place is overwriting that object with another unmanaged entity. To hunt it down, check the rest of the code that sets the profile object on the conversation. I'd look at everything else if you're confident that the query is executing and returning the expected result set.

@zquintana commented on GitHub (Apr 9, 2018): If you've setup with the laravel doctrine package you should have the artisan command `doctrine:schema:validate`. That's the tool that validates your mapping data with Doctrine. I see that the join is suppose to select the profile and load it's relation, but the error you're getting implies that the profile attached to the conversation is not managed. I've used Doctrine for a while and the only times I've seen that happen is when the object is being set accidentally to the property. Generally when a query is made via the entity manager any mapped entities are added to the unit of work right after they're mapped to entities. So if you're getting that error and the you are receiving an entity, it's likely that another process you have in place is overwriting that object with another unmanaged entity. To hunt it down, check the rest of the code that sets the profile object on the conversation. I'd look at everything else if you're confident that the query is executing and returning the expected result set.
Author
Owner

@hskrasek commented on GitHub (Apr 9, 2018):

@zquintana So I used the validate command, had a few unrelated fixed but cleaned some things up. Thanks for the tip!

I think I may have figure out what is going on here. We have multiple databases, and as such we are having to utilize multiple EntityManagers. My repository with the custom query was getting the right entity manager, but my service class was getting the default manager that was missing the context of all the entities that were just fetched.

Second I fixed that, boom everything worked. That was.. fun to figure out. But I highly appreciate the help here

@hskrasek commented on GitHub (Apr 9, 2018): @zquintana So I used the validate command, had a few unrelated fixed but cleaned some things up. Thanks for the tip! I think I may have figure out what is going on here. We have multiple databases, and as such we are having to utilize multiple EntityManagers. My repository with the custom query was getting the right entity manager, but my service class was getting the default manager that was missing the context of all the entities that were just fetched. Second I fixed that, boom everything worked. That was.. fun to figure out. But I highly appreciate the help here
Author
Owner

@zquintana commented on GitHub (Apr 9, 2018):

@hskrasek, yep no problem. Glad you were able to figure it out. Sounded like it something outside scope of the context you originally provided. Happy to hear your figured it out. Can you close your issue to keep this clean?

@zquintana commented on GitHub (Apr 9, 2018): @hskrasek, yep no problem. Glad you were able to figure it out. Sounded like it something outside scope of the context you originally provided. Happy to hear your figured it out. Can you close your issue to keep this clean?
Author
Owner

@hskrasek commented on GitHub (Apr 10, 2018):

@zquintana Sure thing, just left it open incase there was anything else to follow up on.

For anyone else who runs into this, on top of Zachary's suggestions, don't forget to make sure all of your classes are getting the same instance of the EntityManager

@hskrasek commented on GitHub (Apr 10, 2018): @zquintana Sure thing, just left it open incase there was anything else to follow up on. For anyone else who runs into this, on top of Zachary's suggestions, don't forget to make sure all of your classes are getting the same instance of the EntityManager
Author
Owner

@ghost commented on GitHub (Feb 1, 2019):

@hskrasek I've that problem. I'm using an EM for read and other for write. I foudn this error by migrating from doctrine 2.5 to 2.5.11, so maybe, it's a problem of defaults confguration? do you know more about?

@ghost commented on GitHub (Feb 1, 2019): @hskrasek I've that problem. I'm using an EM for read and other for write. I foudn this error by migrating from doctrine 2.5 to 2.5.11, so maybe, it's a problem of defaults confguration? do you know more about?
Author
Owner

@RafaelKr commented on GitHub (Jul 5, 2024):

I had a similar problem and want to leave this here just in case someone stumbles upon this.

In my Symfony project I manually created a Proxy Object by using $this->entityManager->getProxyFactory()->getProxy($entityClass, $id).
But this doesn't attach the object to the EntityManager. After some debugging I found out I need to use $this->entityManager->getReference($entityClass, $id) instead.

@RafaelKr commented on GitHub (Jul 5, 2024): I had a similar problem and want to leave this here just in case someone stumbles upon this. In my Symfony project I manually created a Proxy Object by using `$this->entityManager->getProxyFactory()->getProxy($entityClass, $id)`. But this doesn't attach the object to the EntityManager. After some debugging I found out I need to use `$this->entityManager->getReference($entityClass, $id)` instead.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#5942