-
Notifications
You must be signed in to change notification settings - Fork 934
Skip initialization of lazy properties when setting one #1943
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In its current state, the PR will break the lazy property feature if some custom implementations of entity persisters or tuplizers, or of field interceptors, are used. I do not think it is acceptable for a minor version.
And for a major version, then better directly change the interfaces for forcing everyone to implement the required new methods.
So either working fallback, at worst assuming the old behavior (everything lazy either initialized or uninitialized), should be put in place, or the change should be set for the 6.0 milestone, with modified interfaces rather than new extensions method not supporting every cases.
Either ways, some possible breaking changes will be there and should be mentioned:
Possible breaking changes:
- Setting the value of an unitialized lazy property will no more trigger loading of all the lazy properties of the entity.
- If an unitialized lazy property has got its value set, without any other subsequent lazy property load on the entity, a dynamic update will occur on flush, even if the entity has dynamic updates disabled. This update will occur even if the set value is identical to the currently persisted property value.
Thanks @fredericDelaporte, I've used your fallback suggestion and solved all mentioned issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you planning to do some more changes for keeping it WIP?
I've analized how Hibernate field interceptor works today and I am planning to align some things with it.
for getting initialized lazy fields and So my current plan is to:
About |
Likely because they support custom dirtiness mechanisms, allowing an user to use something else than the default "compare with loaded state" mechanism. Usually, that "something else" is change tracking data like a dirty property per entity's property, set by some interceptor mechanism when a property is set.
But it seems that what our code actually needs is to know about the uninitialized properties, not the initialized ones. They can be computed from each others of course, but better have directly what we need. Aligning on Hibernate helps porting of course, but I do not think it should be done at the cost of getting less optimal code. The first three points are not strongly related to the change done by this PR. I would rather see them done as another PR, something like "Port Hibernate's current field interceptor mechanism". |
…FieldInterceptor for consistency with other members
You are right, will leave as it is, I only renamed the method name in
Agreed, better to have them separated. |
@maca88 can you please clarify in the description what does it mean "related"? |
…erties when setting one
36c2079
to
21d161f
Compare
Description updated. |
@@ -16,8 +16,10 @@ internal static class FieldInterceptorProxyBuilder | |||
private static readonly PropertyInfo AccessorTypeFieldInterceptorProperty = | |||
FieldInterceptorAccessorType.GetProperty(nameof(IFieldInterceptorAccessor.FieldInterceptor)); | |||
private static readonly System.Type FieldInterceptorType = typeof(IFieldInterceptor); | |||
private static readonly System.Type FieldInterceptorExtensionsType = typeof(FieldInterceptorExtensions); | |||
private static readonly MethodInfo FieldInterceptorInterceptMethod = FieldInterceptorType.GetMethod(nameof(IFieldInterceptor.Intercept)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am seeing this a bit late, but I think it should have been removed. It causes the built proxy to use an obsoleted method for getter implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't changed that on puprose as I tried to minimize the performance inpact because of the cast in the extension method. To be honest I didn't test how much the cast will actaully inpact on the performance, so if you know that it is irrelevant we should remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I have mixed feelings on this subject, because the obsolete code in this IL generation case is nearer to what we should have in 6.0 than the non-obsoleted code.
But it feels as a bug that it compiles without failing due to referencing an obsolete symbol. Rider shows it as an error, but the compiler is fine with it. That is maybe a compiler bug for the nameof
case when it refers an obsolete property. In such case the compilation may break on a tooling update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a quick test and it seems that for calling a no-op Intercept
method is twice faster without the cast for a million calls, which is not a big deal as casting a million times takes approx. 9ms. So we could remove it in order to avoid showning as an error in Rider. It seems that the compiler is not smart enough to detect that the only reference that the nameof
references is an obsolete member.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or you can suppress the warning with directives around that line.
The aim of this PR is to have the ability to update uninitialized lazy properties without triggering their initialization, which is required by #1922 in order to update the fetched lazy properties.
This PR also modifies the behavior for properties mapped as lazy="no-proxy" to not be initialized when set, which solves the issue where a
LazyInitializationException
occurred when setting the property value while the session is disconnected (#1267 first point).