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

Fix loop detection for associations with fetch="join" mapping #2718

Merged
merged 32 commits into from
Sep 6, 2022

Conversation

deAtog
Copy link
Contributor

@deAtog deAtog commented Mar 31, 2021

Fixes #2201

@deAtog deAtog force-pushed the GH-2201 branch 4 times, most recently from 0b615a4 to deaa8f0 Compare April 1, 2021 04:39
@fredericDelaporte

This comment has been minimized.

@deAtog

This comment has been minimized.

@deAtog deAtog force-pushed the GH-2201 branch 6 times, most recently from 0f32f3e to bfd6887 Compare April 5, 2021 20:17
@deAtog deAtog changed the title Disable duplicate join detection. Fix invalid SQL generation due to JoinWalker and add an option to disable detection of fetch loops. Apr 6, 2021
@deAtog deAtog force-pushed the GH-2201 branch 3 times, most recently from 255c21e to ebd0c2f Compare April 7, 2021 14:56
@deAtog deAtog marked this pull request as ready for review April 7, 2021 20:29
@deAtog
Copy link
Contributor Author

deAtog commented Apr 7, 2021

@fredericDelaporte This should address the issue identified in issue #2201 and provide a mechanism for users to disable the loop detection which results in an 1+N case when the entity graph does not have a loop, but the query does. It should be safe for users to disable the loop detection whenever they do not have implicit loops in their entity graph or when they have explicitly set max_fetch_depth.

Copy link
Member

@bahusoid bahusoid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do a proper review when I have time but it looks pretty good at quick glance. Some notes:
You shouldn't delete protected members (IsJoinable) - it's a breaking change. Mark it as obsolete instead. And better to get rid of formatting changes in unrelated places.

You disabled in tests loop detection but reported issue is actually related to old loop detection logic. So reported issue is actually not tested. Please add tests to verify that proper entities are initialized when loop detection is enabled.

Use additionally NHibernateUtil.IsInitialized in tests to verify that entity is actually initialized. Something like:

Assert.That(p.Parent.Details, Is.Not.Null);
Assert.That(NHibernateUtil.IsInitialized(p.Parent.Details));

@deAtog
Copy link
Contributor Author

deAtog commented Apr 9, 2021

@bahusoid With a one-to-one relationship both the old and new behavior always initialize the one-to-one, but they cause additional EntityFetch's to occur.

The changes to the JoinWalker are well tested by every other test in the suite. A test that verifies the old behavior vs the new behavior would be very similar to those that failed after modifying it. Those tests only passed due to the side affects of the loop detection and depth-first nature of the old JoinWalker. Those tests did the following:

  1. Query for a Contract
    a. Contract has fetch="join" set for Subcontracts and Parties
    b. Subcontracts is of type Contract and is initialized before Parties. As a result, Contract.Subcontract.Parties was was being initialized but Contract.Parties was not.
  2. Deleted parties for the Contract
  3. Deleted the Contract
    a. Deleting a Contract cascade deletes Subcontracts, Parties, and Infos.

After the changes to the JoinWalker, Contract.Subcontract.Parties is not initialized but Contract.Parties is. Attempting to delete the Contract after deleting all Parties threw an exception because the Contract could not cascade delete the Parties that were associated with it. If these tests had originally asserted that Contracts.Parties was initialized they would have failed.

Swapping steps 1 and 2 above, ensures that the loaded Contract does not have any Parties associated with it and the deletion of the Contract succeeds without issue.

@deAtog
Copy link
Contributor Author

deAtog commented Apr 12, 2021

@bahusoid I'm going to re-order/combine these commits to make it easier to review. I'll let you know when it is ready again. The recent commits revert some of the original modifications to JoinWalker to avoid using the queue for anything but required joins. This eliminates the overhead involved in the simplest of cases where no joins are present.

bahusoid
bahusoid previously approved these changes Aug 21, 2022
@hazzik hazzik dismissed stale reviews from fredericDelaporte and bahusoid via 5043ea4 August 21, 2022 21:41
hazzik
hazzik previously approved these changes Aug 22, 2022
bahusoid
bahusoid previously approved these changes Aug 22, 2022
@bahusoid bahusoid dismissed stale reviews from hazzik and themself via 7ce6da3 August 22, 2022 06:01
@hazzik hazzik changed the title Fix invalid SQL generation due to JoinWalker and add an option to disable detection of fetch loops. Fix invalid SQL generation due to JoinWalker and add an option to disable detection of fetch loops Aug 26, 2022
@bahusoid bahusoid changed the title Fix invalid SQL generation due to JoinWalker and add an option to disable detection of fetch loops Fix loop detection for associations with fetch="join" mapping Sep 6, 2022
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.

Fetch Join generates incorrect SQL joins for the same entity type
4 participants