Skip to content
Advertisement

@Column settings in case of externally managed database schema

When externally managing the database schema (e.g. with Liquibase), in addition to specifying the Liquibase changesets, you have to help Hibernate understand your data structure using JPA annotations.

While some annotations concern higher level abstractions of the underlying data like @Embedded or @OneToMany, other lower level annotations, such as @Column(length = 255, nullable = false), seem only to represent what is already defined in the underlying database schema (varchar(255) not null). Therefore it feels redundant to specify both, and it raises several questions for which I couldn’t find a clear answer in the docs:

[main question] Which @Column settings (besides name, insertable and updatable) are only used for DDL creation and could therefore be safely omitted if the database schema is managed externally?
My guess would be: columnDefinition, length, precision and scale, but I’m unsure if Hibernate makes some other internal use of those. What about nullable and unique, does Hibernate take these into account for example to optimize queries, or could those be left out as well?

As a test, I tried to write null to a non-nullable database column, and the only difference in specifying @Column(nullable = false) was that the exception would originate from the EntityManager instead of the database driver, which wouldn’t matter much to the application (edit: assuming it is an exception case).

[side question 1] Does Hibernate assume uniqueness and non-nullability on single-column primary keys so the @Column(unique = true, nullable = false) settings could be omitted on properties that also have @Id?

[side question 2] Since Hibernate is capable of inspecting the database schema (e.g. when using hbm2ddl.auto=validate), can it be configured to extract the type and constraint information it needs from the underlying schema so that settings in @Column could be omitted?

Advertisement

Answer

Hibernate does make use of some of the annotation members, especially as of version 6. I would suggest you to look into a tool like JPABuddy which can generate Liquibase changesets based on diffs between your entity and liquibase model. In the past, I implemented such a diffing in a JUnit test. The test creates two databases, one through hbm2ddl and one through the liquibase model. Finally, it diffs the two and if there is a difference, fails the test, reporting the XML serialized form of the diff.

This way, both models stay in sync easily and you also don’t need hbm2ddl validate.

Here you can see the runtime model receiving information like length, precision, scale and columnDefinition: https://github.com/hibernate/hibernate-orm/blob/6.1.3/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java#L262

And here you can see this information being used: https://github.com/hibernate/hibernate-orm/blob/6.1.3/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java#L3629

This particular use is for casting parameters that infer the type of a mapping attribute i.e. in a query like ... where alias.attribute = :param. Some databases might require that the parameter marker is wrapped by a cast in SQL under certain circumstances.

So this was just a small example of how Hibernate already uses some of this information. You’ll probably find some other uses if you study the Hibernate code.

Advertisement