Skip to content

Conversation

onobc
Copy link
Contributor

@onobc onobc commented Feb 7, 2021

Checks 'javax.persistence.schema-generation.database.action' before returning default ddlAuto in HibernateProperties.

Fixes gh-25054

…eturning default ddlAuto in HibernateProperties

Fixes gh-25054
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 7, 2021
@snicoll snicoll added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Feb 9, 2021
@snicoll snicoll added this to the 2.3.9 milestone Feb 9, 2021
@snicoll snicoll self-assigned this Feb 9, 2021
Copy link
Member

@snicoll snicoll left a 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;
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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"));
Copy link
Member

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).

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Feb 9, 2021
@snicoll snicoll modified the milestones: 2.3.9, 2.3.x Feb 9, 2021
@onobc
Copy link
Contributor Author

onobc commented Feb 9, 2021

Thanks for that info @snicoll . I will make the adjustments sometime w/in the next 24 hrs.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 9, 2021
@snicoll snicoll added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Feb 9, 2021
return ddlAuto;
}
String ddlDatabaseAction = existing.get(AvailableSettings.HBM2DDL_DATABASE_ACTION);
if (ddlDatabaseAction != null) {
Copy link
Contributor Author

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.

Copy link
Contributor Author

@onobc onobc Feb 13, 2021

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:

  1. 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)
  2. 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,
Copy link
Contributor Author

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;
Copy link
Contributor Author

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) {
Copy link
Contributor Author

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");
Copy link
Contributor Author

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.

@onobc onobc requested a review from snicoll February 19, 2021 16:58
@snicoll snicoll removed the status: waiting-for-feedback We need additional information before we can continue label Mar 7, 2021
@snicoll snicoll modified the milestones: 2.3.x, 2.3.10 Mar 22, 2021
@snicoll
Copy link
Member

snicoll commented Mar 22, 2021

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 master anymore.

@wilkinsona wilkinsona changed the title Checks 'javax.persistence.schema-generation.database.action' when determining DDL auto default javax.persistence.schema-generation.database.action is ignored when checking if default DDL auto setting should be applied Apr 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants