This article summarizes what I was addicted to while developing the application, and if I could find it, the cause and solution. There may be cases where the problem is in this article, but the usage is wrong in the first place, or there is a better solution.
As is usually the case with databases, there can be issues with the Hibernate implementation.
@Entity
class Parent {
@Id
Long id;
@NatulalId
Integer key;
String firstName;
String lastName;
}
@Entity
class Child {
@Id
Long id;
@ManyToOne
@JoinColumn(name = "parent_key",referencedColumnName = "key")
Parent parent;
}
In the above usage where the PK recommended by Hibernate itself is the surrogate key and the natural key is specified by @NaturalId
, the key is specified as Unique within the range of the JPA specification, and instead of the id. You want it to function as a foreign key.
If you associate with a natural key, an error will occur due to cast involvement when executing child.getParent () etc. [^ 1]
[^ 1]: It doesn't seem to happen all the time, and it seems that questions about that are often posted.
Official issue tracker HHH-7668
Make the referenced entity (Parent in the above) Sirializable. With this in mind, it may be safer for all entities used in Hibernate to be Sirializable.
A quick look at the issue tracker shows that if you associate it with a unique column that is not PK, you may encounter other problems.
Due to JPA specifications, Sirializable is not required when an entity is exchanged only with DB, but Sirializable of an entity is required when it is used within the scope of JavaEE, such as saving it as an object in an HTTP session. It seems like. Considering that an error occurs in an unexpected place, it seems that it is desirable to be Sirializable.
Because the entity of the Lazy specified property that Jackson is accessing when serializing is a Hibernate proxy
Add the Jackson plug-in for the Hibernate version. Spring Boot depends on Hibernate and Jackson by default, so why isn't this included? [^ 2] [^ 2]: I noticed while writing the article, but it is included in Spring Data REST Web MVC ... Why? Stack Overflow: No serializer found for ...? Stack OverFlow: Spring Jackson suppresses Lazy attribute Everyone is having a hard time.
Solving the problem that Jackson serialization of Spring JPA entity also triggers Lazy The above is a very straightforward explanation and solution.
So just in case, it's Plugin GitHub. The content is not very kind. Incidentally, Explanation of output control by Jackson annotation (infinite loop workaround) introduced in the above GitHub.
This is a specification story. It's not a bug.
~~ The default naming strategy is processed after JPA annotations ~~
~~ If an annotation that specifies a JPA (≒ Hibernate) table name or column name is used simply because of the priority problem, an error will occur because the column name conversion from the field name has not been processed. ~~
I didn't understand the specifications enough. Hibernate will generate the DB column name through a two-step conversion.
The current Spring default is
Generation of logical name
--Get class name and field name as ** logical name **
--If specified by @ Column
or @ Table
, change the character string to ** logical name **
Generation of physical name --Replace period with underscore --Replace camel case with snake case
It is set as.
Since the character string specified by @ Column
or @ Table
is changed to ** logical name **, if the field or class name is specified in camel case, the name specified in the annotation should not be changed to camel case. Must not be. If a physical name (that is, a snake case) is specified here, "Table [table name] contains physical column name [column name] referred to by multiple logical column names:" (logical corresponding to the physical column name of the table) I have two names) and I get an error.
If the column name etc. is specified in the ~~ JPA annotation, the name must be specified in the field with @Column
. I can't cut corners more than I expected. ~~ [^ 3]
[^ 3]: ~~ I think it can be solved by customizing on the Hibernate side. ~~
Read the specifications and error messages properly.
Since the physical name is generated in all lowercase letters, it is better to use uppercase column names and table names.
apprication.yaml
spring:
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
(The logical name is used as the physical name as it is). However, Spring ImplicitNamingStrategy, which Spring uses by default, uses Hibernate's default ImplicitNamingStrategyJpaCompliantImpl almost as it is, so if you use the property name of camel case, it will be the column name of camel case as it is. Refer to stackoverfrow: Hibernate naming strategy example and select the closest one and adjust it with annotations. think. If it's not enough to use Hibernate's strategy, you'll have to implement it yourself. reference: Adjusted with Physical Naming Strategy Adjusted with ImplicitNamingStrategyJpaCompliantImpl
This is not a problem, it's a tip. It's a convenient way to create an entity that wants to keep the actual value of the key in a property and follow the association only when needed.
Disable update and insert of related entities with @ JoinColumn
@Entity
class Parent {
@Id
Long id;
@NatulalId
Integer key;
String firstName;
String lastName;
}
@Entity
class Child {
@Id
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_key",referencedColumnName = "key",
insertable = false, updatable = false)
Parent parent;
@Column(name="parent_key")
Integer parentKey;
}
By making it a class like the above, it is possible to refer to the parent while holding the key directly, and it is possible to prevent the child from updating the parent. When updating the reference, directly change the value of the key field (parentKey in this example). This shape works very well for objects that reference master data.