简体   繁体   中英

Hibernate/SQL SERVER java.sql.SQLException: Cannot insert NULL values into column that has default value

having Hibernate and SQL Server, I'm facing a problem when I'd like to update an entity called Client . The Client entity has auditing fields like the name of current user who create/update this latter and the date times when these operations occurs. The problem here is that when an update happens, the java.sql.SQLException is thrown, below the log for more details:

Caused by: java.sql.SQLException: Cannot insert the value NULL into column 'IS_SUPPRIMER', table 'IJSS_DB.dbo.TF_CODE_PAIE'; column does not allow nulls. UPDATE fails. at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:368) ~[jtds-1.2.4.jar:1.2.4] at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2820) ~[jtds-1.2.4.jar:1.2.4] at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2258) ~[jtds-1.2.4.jar:1.2.4] at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:632) ~[jtds-1.2.4.jar:1.2.4] at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:584) ~[jtds-1.2.4.jar:1.2.4] at net.sourceforge.jtds.Z84BEFFD3A0D49636A58CE6080CAA87C 7Z.JtdsStatement.executeSQL(JtdsStatement.java:546) ~[jtds-1.2.4.jar:1.2.4] at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:506) ~[jtds-1.2.4.jar:1.2.4] at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3421) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.Z93F725A07423FE1C889F448B33D2 1F46Z:3283) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3695) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:149) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at Z93F725A07423FE1C8 89F448B33D21F46Z.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[?:?] at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:108) ~[hibernate-core-5.4 .10.Final.jar:5.4.10.Final] at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1344) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:435) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3221) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2389) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.engine.Z84BEFFD3A0D49636A58CE6080CAA87 C7Z.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcRe sourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final] at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:534) ~[spring-orm-5.2.3.RELEASE.jar:5.2.3.RELEASE]... 98 more

Note that IS_SUPPRIMER column is among auditing fields that indicates if this column is deleted or not (IS_SUPPRIMER=true /deleted, IS_SUPPRIMER=false/ not deleted),as result we make a logical remove and not a physical remove.

What's strange here is that the client entity which is mapped to TF_CLIENT table has a column named IS_SUPPRIMER with default value, below the script:

CREATE TABLE [dbo].[TF_CLIENT] (
    [CLT_ID] [bigint] IDENTITY(1,1) NOT NULL,
    [CLT_LIBELLE] [nvarchar](50) NOT NULL,
    [CLT_DT_OUVERTURE] [date] NOT NULL,
    [CLT_DT_FERMETURE] [date],
    [CLT_B_ACTIF] [bit] CONSTRAINT DF_TF_CLIENT_B_ACTIF DEFAULT 1 NOT NULL,
    [DATE_CREATION] [datetime2](3),
    [DATE_MODIFICATION] [datetime2](3),
    [DATE_SUPRESSION] [datetime2](3),
    [AUTEUR_CREATION] [nvarchar](100),
    [AUTEUR_MODIFICATION] [nvarchar](100),
    [AUTEUR_SUPRESSION] [nvarchar](100),
    [IS_SUPPRIMER] [bit] CONSTRAINT DF_TF_UTILISATEUR_IS_SUPPRIMER DEFAULT 0 NOT NULL
    CONSTRAINT UQ_CLT_LIBELLE UNIQUE(CLT_LIBELLE),
    CONSTRAINT PK_TF_CLIENT PRIMARY KEY CLUSTERED
(
[CLT_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    END

so why updating a such Client entity will require a value of IS_SUPPRIMER which has already a default value?

Below the code of Auditing class:

@Embeddable
@Getter
@Setter
@NoArgsConstructor
public class FieldAuditing implements Serializable {

    @Column(name = "DATE_CREATION")
    private Instant createdAt;

    @Column(name = "DATE_MODIFICATION")
    private Instant updatedAt;

    @Column(name = "DATE_SUPRESSION")
    private Instant deletedAt;

    @Column(name = "AUTEUR_CREATION", length = 100)
    private String createdBy;

    @Column(name = "AUTEUR_MODIFICATION", length = 100)
    private String updatedBy;

    @Column(name = "AUTEUR_SUPRESSION", length = 100)
    private String deletedBy;

    @Column(name = "IS_SUPPRIMER")
    private Boolean isDeleted = false;

    @PrePersist
    public void prePersist() {
        if (this.isDeleted == null)
            setIsDeleted(Boolean.FALSE);
        setCreatedAt(Instant.now());
        setCreatedBy(LoggedInUser.get());
    }

    @PreUpdate
    public void preUpdate() {
        if (this.isDeleted == null)
            setIsDeleted(Boolean.FALSE);
        setUpdatedAt(Instant.now());
        setUpdatedBy(LoggedInUser.get());
    }

}

Also the Client Entity class:

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name="TF_CLIENT", schema="dbo")
public class Client implements Serializable {

    private static final long serialVersionUID = 8832848102370267801L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(name = "CLT_ID", nullable = false)
    private Long id;

    @Column(name = "CLT_LIBELLE", nullable = false, length = 50, unique = true)
    private String libelle;

    @Temporal(TemporalType.DATE)
    @Column(name = "CLT_DT_OUVERTURE", nullable = false)
    private Date dateOuverture;

    @Temporal(TemporalType.DATE)
    @Column(name = "CLT_DT_FERMETURE")
    private Date dateFermeture;

    @Column(name = "CLT_B_ACTIF")
    private boolean isActif;

    @Embedded
    private FieldAuditing fieldAuditing = new FieldAuditing() ;

    @JsonIgnore
    @OneToMany
    @Builder.Default
    @JoinColumn(name="CLI_ID")
    Set<Etablissement> etablissements = Collections.emptySet();

    @JsonIgnore
    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name="CLI_ID")
    @Builder.Default
    @Setter(AccessLevel.NONE)
    Set<CodePaie> codePaies = new HashSet<>();

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, mappedBy = "client", orphanRemoval = true)
    @Builder.Default
    @Setter(AccessLevel.NONE)
    Set<ClientAction> clientActions = Sets.newHashSet();

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, mappedBy = "client", orphanRemoval = true)
    @Builder.Default
    @Setter(AccessLevel.NONE)
    Set<ClientEtat> clientEtats = Sets.newHashSet();

    public void addClientActions(Set<ClientAction> clientActions) {
        clientActions.forEach(clientAction -> clientAction.setClient(this));
        this.clientActions.addAll(clientActions);
    }

    public void addClientEtats(Set<ClientEtat> clientEtats) {
        clientEtats.forEach(etat -> etat.setClient(this));
        this.clientEtats.addAll(clientEtats);
    }

    public void addCodePaies(Set<CodePaie> codePaies) {
        codePaies.forEach(codePaie -> codePaie.setClient(this));
        this.codePaies.addAll(codePaies);
    }

    public void removeAllCodePaie() {
        codePaies.forEach(codePaie -> codePaie.setClient(null));
        this.codePaies.clear();
    }

}

Finally the code snippet of updating Client entity:

 private ClientDto save(ClientDto clientDto, Client client) {
        startDateShouldBeBeforeEndDate(clientDto);
        hasUniqueCodePaies(clientDto.getCodePaies());
        Client clientSaved = clientRepository.save(clientMapper.toEntity(clientDto, client));
        clientMapper.addOrRemoveClientActions(clientDto, clientSaved);
        clientMapper.addOrRemoveClientEtats(clientDto, clientSaved);
        clientRepository.save(clientSaved);
        clientDto.setId(clientSaved.getId());
        return clientDto;
    }

Kindly, could you take a look at my issue description and help me.

I'm thankful for any help.

The exception indicates that the problem lies in TF_CODE_PAIE not TF_CLIENT. I would guess that TF_CODE_PAIE.IS_SUPPRIMER does not have a default value.

JPA execute query with all field of table. So, when you don't set isDeleted field then it null and JPA execute query with null value for isDeleted field that's why you got the error.

That's means you are trying to set null value in not-null field which is wrong. Default means when you don't set the field in sql query it set by default value. Use this

@Column(name = "IS_SUPPRIMER", columnDefinition = "bit default 0")
private Boolean isDeleted;

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