![](/img/trans.png)
[英]java.sql.SQLException: Cannot insert the value NULL into column
[英]Hibernate/SQL SERVER java.sql.SQLException: Cannot insert NULL values into column that has default value
擁有 Hibernate 和 SQL 服務器,當我想更新一個名為Client的實體時遇到問題。 客戶端實體具有審計字段,例如創建/更新后者的當前用戶的名稱以及這些操作發生的日期時間。 這里的問題是,當更新發生時,會拋出java.sql.SQLException ,在日志下方以獲取更多詳細信息:
引起:java.sql.SQLException:無法將值 NULL 插入列 'IS_SUPPRIMER',表 'IJSAIES._CODE;。 列不允許空值。 更新失敗。 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] 在 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.更新或插入(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] 在 Z93F725A074 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] 在 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 更多
請注意, IS_SUPPRIMER列是指示該列是否被刪除的審計字段(IS_SUPPRIMER=true /deleted,IS_SUPPRIMER=false/未刪除),因此我們進行了邏輯刪除而不是物理刪除。
這里奇怪的是,映射到TF_CLIENT表的客戶端實體在腳本下方有一個名為IS_SUPPRIMER的默認值列:
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
那么為什么更新這樣的客戶端實體需要一個已經有默認值的IS_SUPPRIMER值呢?
在審核 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());
}
}
還有客戶端實體 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();
}
}
最后是更新客戶端實體的代碼片段:
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;
}
請您看看我的問題描述並幫助我。
我很感激任何幫助。
異常表明問題出在 TF_CODE_PAIE 而不是 TF_CLIENT。 我猜 TF_CODE_PAIE.IS_SUPPRIMER 沒有默認值。
JPA 對表的所有字段執行查詢。 因此,當您不設置isDeleted
字段時,它 null 和 JPA 使用 null 值執行查詢isDeleted
字段,這就是您收到錯誤的原因。
這意味着您正在嘗試在錯誤的非空字段中設置 null 值。 默認表示當您未在 sql 查詢中設置該字段時,將其設置為默認值。 用這個
@Column(name = "IS_SUPPRIMER", columnDefinition = "bit default 0")
private Boolean isDeleted;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.