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

Fixed a situation where unnecessary sql UPDATE statements were issued fo... #814

Closed
wants to merge 2 commits into from

Conversation

iBiryukov
Copy link

...r unchanged DateTime objects

computeChangeSet method in unitOfWork compares original and new data using 'identical' (===) operator. This works well, except for DateTime objects.

Two different DateTime objects that contain the same data, should not trigger an unnecessary UPDATE query.

I made changes to account for this case.

@doctrinebot
Copy link

Hello,

thank you for creating this pull request. I have automatically opened an issue
on our Jira Bug Tracker for you. See the issue link:

http://www.doctrine-project.org/jira/browse/DDC-2725

We use Jira to track the state of pull requests and the versions they got
included in.

@Ocramius
Copy link
Member

Ocramius commented Oct 6, 2013

sorry for closing eagerly. Again, doctrine won't support hardcoded custom checks. see http://stackoverflow.com/questions/15486402/doctrine2-orm-does-not-save-changes-to-a-datetime-field/15488230#15488230

You will need for support of value objects to see this happening.

@Ocramius Ocramius closed this Oct 6, 2013
@iBiryukov
Copy link
Author

Well, Doctrine clearly shows wrong behaviour. It's executing an update statement when no update statement is required.
If you don't like my solution, how about we open a bug and wait until somebody else comes up with something better? Or have a conversation about possible solutions here.

Thanks for the link. It describes yet another issue, related to the same line of code, but is not exactly the same, as what I was talking about.

@Ocramius
Copy link
Member

Ocramius commented Oct 6, 2013

The idea is to have comparators (just an idea so far) do the work. So far we didn't introduce them because they only solve edge cases and cause great performance overhead. I was working on something in my ChangeSet project, but it's currently on hold.

@AlexeyKosov
Copy link

So far we didn't introduce them because they only solve edge cases and cause great performance overhead.

Great performance overhead is generating redundant UPDATE queries which, obviously, take some time to execute.

@Ocramius
Copy link
Member

Ocramius commented Aug 3, 2017

Yes, but we can't fix it without a massive amount of overhead for the 99% use-case scenario.

@AlexeyKosov
Copy link

Ok, of course, it's up to you to make strategic decisions, but it could be solved without any massive overhead. 1 if condition for checking if the comparable items are both objects and have the same type and another 1 to check if there's a comparator (or however you call it) registered for that class. In other words, it could be implemented as an optional feature, i.e. if one wanted to enable it for, say, DateTime or Money objects, they could inject a comparator for the specific class which would be responsible for comparing objects of this type. All other comparisons could still be done using ===.
IMHO, a couple of simple checks are much less evil than executing tons of unnecessary update queries.

@Ocramius
Copy link
Member

Ocramius commented Aug 3, 2017 via email

@AlexeyKosov
Copy link

Your point makes sense and, indeed, the ideal solution would be comparing the values in the form they go to the database, rather than objects.
I was just concerned not about the mutability/immutability dichotomy, but about the case when a different object instance, however, having the same value, is set to an entity.

$entity->setCreatedAt(new DateTime('2017-08-04 00:00:00'));
$em->flush();
$entity->setCreatedAt(new DateTime('2017-08-04 00:00:00'));
$em->flush(); // unneccesary query

Currently, I have to wrap all setters with something like this:

public function setCreatedAt(DateTime $createdAt)
{
    if ($createdAt != $this->createdAt) {
        $this->createdAt = $createdAt;
    }
}

Obviously, looks like a dirty hack. It's great that you managed to avoid such hacks in Doctrine itself, and hopefully, at some point you'll manage to allow Doctrine's users get rid of those in application business-logic.

@alcaeus
Copy link
Member

alcaeus commented Aug 4, 2017

@AlexeyKosov this issue can't be solved - just because a !== b && a == b is true doesn't mean Doctrine should just not update it. This is part of your application logic: someone sets a new object instance but your application wants to treat it the same. That belongs exactly where you currently have it: in your model.

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

Successfully merging this pull request may close these issues.

None yet

5 participants