-
Notifications
You must be signed in to change notification settings - Fork 41.5k
javax.persistence.schema-generation.database.action is ignored when checking if default DDL auto setting should be applied #25129
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
…eturning default ddlAuto in HibernateProperties Fixes gh-25054
...figure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java
Outdated
Show resolved
Hide resolved
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.
Thanks for the PR. I don't think handling the spec value as a ddl auto value is legit. See further comments for details.
} | ||
String ddlDatabaseAction = existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION); | ||
if (ddlDatabaseAction != null) { | ||
return ddlDatabaseAction; |
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.
The problem here is that ddlDatabaseAction
is not, strictly speaking, a ddlAuto
. The values are close but not the same. Considering that, I don't think that change is correct.
Rather, I think we should review this method altogether and set a ddl-auto only if necessary, calling the supplier if need to be. This could prove tricky as we've had a few regressions in this area.
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.
@snicoll I found the mapping from JPA (javax.persistence.schema-generation.database.action
) to HBM (hibernate.hbm2ddl.auto
) here.
There is a direct mapping from each possible value of the JPA property to its corresponding HBM property.
JPA | HBM | Description |
---|---|---|
none | none | No action will be performed |
create | create-only | Database creation will be generated |
drop | drop | Database dropping will be generated |
drop-and-create | create | Database dropping will be generated followed by database creation |
The code in CREATE_ONLY and CREATE confirms this as well.
Since this ticket is about setting the HBM default value from the JPA value, I think the above grid gives us what we want to use. What do you think?
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.
Since this ticket is about setting the HBM default value from the JPA value, I think the above grid gives us what we want to use. What do you think?
Unfortunately, I don't think this statement is accurate. IMO, this issue is about not setting a default ddlAuto value if the JPA spec property is set. I think translating one to the other is also a completely different feature that I am not convinced we want to provide.
void defaultDdlAutoIsNotInvokedIfJpaDatabaseActionPropertyIsSet() { | ||
this.contextRunner | ||
.withPropertyValues("spring.jpa.properties.javax.persistence.schema-generation.database.action=create") | ||
.run(assertDefaultDdlAutoNotInvoked("create")); |
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 don't think this test is correct. The spec states that drop-and-create
is a valid value. If you'd rewrite this test with this, you'd have to assert that ddl auto was set with it, which is not a valid ddlAuto.
Rather, we should check the ddl auto isn't set (but the spec property is).
Thanks for that info @snicoll . I will make the adjustments sometime w/in the next 24 hrs. |
…on' before using it as hbm2ddl default
return ddlAuto; | ||
} | ||
String ddlDatabaseAction = existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION); | ||
if (ddlDatabaseAction != null) { |
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.
Strict Approach
I chose a strict approach that only considers valid JPA database action values (none, create, drop, drop-and-create) - each of which has a well-known counterpart hbm2ddl.auto
value. Any other values, including valid HBM specific values are ignored and the defaultDdlAuto provider kicks in.
More Relaxed Approach
However, Hibernate seems to be verify forgiving and relaxed when it comes to these values. It seems to use the JPA/HBM properties interchangeable. It prefers the JPA properties but also allows HBM values to be set on the JPA property.
A more relaxed approach would be to allow whatever values are set on the JPA property to be used as the default ddl auto and simply handle the 2 JPA special cases: create -> create-only
and drop-and-create -> create
.
Anyways, let's continue the discussion.
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.
Misconception
Ahh ok, I misunderstood the issue. I think my misconception was that the ddl-auto property had to be set to something even if the db-action was set.
Rather, I think we should review this method altogether and set a ddl-auto only if necessary,
I interpreted this to mean set the ddl-auto property if the db-action was set to a value that was a valid ddl-auto
When checking for a user-provided setting before configuring the default setting, I think we need to consider javax.persistence.schema-generation.database.action as well as hibernate.hbm2ddl.auto.
I interpreted "configuring the default setting" as setting the ddl-auto property. Which is true but IFF the user did not already specify a ddl-auto or db-action. If the user set it already under spring.jpa.
then there is no need for us to do anything - it will flow down to HB8 and all is well.
Silver lining
I learned quite a bit about the 2 properties and how we use them and how HB8 uses them.
Third time's a charm
Pivoting here shortly and doing the following:
- If db-action property is set, do not set a default ddl-auto (we do not require db-auto to be set if db-action is set)
- Adjust tests
Question 1)
I feel like it would be helpful to briefly mention this property in the docs. It's not mentioned anywhere but we do support it and looking into the HB8 code they seem to prefer that property over the legacy HB8 specific one. Thoughts?
Question 2)
I noticed that currently we remove the ddl-auto if the default came back as "none" - which could also be from the user setting it to "none". I understand this has no functional impact because the property default is "none". I am curious as to why? Should we do the same for the db-action property?
My mild concern on removing the property when user has explicitly set it to none is this:
- User sets ddl-auto to "none"
- We remove it prior to passing through to HB8
- User steps through HB8 code in debugger
- User says "I set ddl-auto, why is it not here?"
|
||
@ParameterizedTest | ||
@MethodSource("validJpaDatabaseActionsToExpectedHbmValues") | ||
void defaultDdlAutoIsNotInvokedIfJpaDatabaseActionPropertyIsSetToValidJpaValue(String jpaDatabaseAction, |
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.
Of course, these tests all reflect the "Strict Approach" outlined above.
|
||
private String determineDdlAuto(Map<String, String> existing, Supplier<String> defaultDdlAuto) { | ||
if (existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION) != null) { | ||
return null; |
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.
If the user specified db-action, respect that, do not set any ddl-auto default.
} | ||
|
||
private String determineDdlAuto(Map<String, String> existing, Supplier<String> defaultDdlAuto) { | ||
if (existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION) != null) { |
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 made the db-action property take precedence over the hbm property to be consistent w/ Hibernate.
this.jpaProperties.getProperties(), new HibernateSettings().ddlAuto(defaultDdlAuto)); | ||
return hibernate.containsKey("hibernate.hbm2ddl.auto"); | ||
return hibernate.containsKey("hibernate.hbm2ddl.auto") || !hibernate | ||
.getOrDefault("javax.persistence.schema-generation.database.action", "none").equals("none"); |
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 curious as to why? Should we do the same for the db-action property?
I found out what relies on the removed key. I have added the db-action property to this check to ensure we have consistent behavior when the user is setting only the db-action property to drive db schema creation. I also added tests to verify the cases.
…ase.action' is specified
Thanks @Bono007. I've polished the PR in c2f452a. One thing to note is that the Hibernate property should take precedence over the JPA one (as noted by @wilkinsona in the original issue) and the proposal did the opposite. I've also reworked the tests to focus on the vendor properties as it felt more focused and the event doesn't exist on |
Checks 'javax.persistence.schema-generation.database.action' before returning default ddlAuto in HibernateProperties.
Fixes gh-25054