简体   繁体   中英

Why Hibernate ignores not-null constraint?

I have faced interesting behaviour of Hibernate. Can somebody explain me why this happens?

Technology stack: Java 11 / Spring boot [2.3.2.RELEASE] / Spring data [2.3.2.RELEASE] / Hibernate [5.4.18.Final].

I have a table created by liquibase:

<changeSet id="create-persons-table" author="author">
    <createSequence sequenceName="persons_seq"/>
    <createTable tableName="persons">
        <column name="id" type="bigint" defaultValueSequenceNext="persons_seq"/>
        <column name="name" type="varchar(255)"/>
        <column name="lastname" type="varchar(255)"/>
        <column name="es_identification" type="varchar(500)">
            <constraints nullable="false"/>
        </column>
        <column name="person_type" type="varchar(255)"/>
    </createTable>
</changeSet>

I have three entities. Base entity, common entity and country-specific entity:

@Getter
@Setter
@MappedSuperclass
public abstract class BaseEntity {
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "seq_gen")
    private Long id;
}
@Entity
@Getter
@Setter
@NoArgsConstructor
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "person_type")
@SequenceGenerator(name = "seq_gen", sequenceName = "persons_seq", allocationSize = 1)
@Table(name = "persons")
public class Person extends BaseEntity {
    private String name;
    private String lastname;
}
@Entity
@NoArgsConstructor
@DiscriminatorValue("ES")
@Getter
@Setter
public class EsPerson extends Person {
    @Column(name = "es_identification", nullable = false)
    private String esIdentification;
}

and I have corresponding repositories for them:

@NoRepositoryBean
interface BaseRepository<T extends BaseEntity> extends JpaRepository<T, Long> {
    Optional<T> findById(Long id);

    default T requireById(Long id) {
        checkNotNull(id, "id cannot be null");
        return findById(id).orElseThrow(EntityNotFoundException::new);
    }
}
public interface PersonRepository extends BaseRepository<Person> {
}
public interface EsPersonRepository extends BaseRepository<EsPerson> {
}

So the magic (for me) starts when I'm trying to save the EsPerson entity.

var person = new EsPerson();
person.setName("name");
person.setLastname("lastname");
person.setEsIdentification("es-identification");

esPersonRepository.save(esPerson);

In debug mode I see that all properties are not null. But when I'm saving I've got org.postgresql.util.PSQLException: ERROR: null value in column 'es_identification' violates not-null constraint .

I have turned on sql logs and I see that hibernate INSERTs "name", "lastname" and null. After that I've turned off not-null constraint on "es_identification" column and I see that Hibernate firstly INSERTs "name", "lastname", null and after that UPDATEs "es_identification" and sets corresponding value.

So this looks really strange for me. Why Hibernate does not inserts all values in one action? And why it ignores "not-null" constraint?

Please, keep in mind that it is big enough project, so maybe I have missed some important things here. Just trying to keep example as simple as possible.

Why Hibernate acts like that is an implementation-specific question. The bottom line is: not-null constraints are not allowed for child properties in single-table inheritance, and Hibernate is free to operate under that assumption.

The reason is, of course, that the columns corresponding to child properties are necessarily NULL when inserting the parent entity record.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM