Java 将外键引用设置为null以使用spring boot清除关系
我是spring boot应用程序开发新手,面临以下问题 我正在使用一个应用程序,在该应用程序中,我正在开发要跟踪的问题。每个问题都可以关联到特定类别。但是,将问题与特定类别关联不是强制性的 可以创建问题,而无需将其与任何特定类别关联。 可以更新问题以查找现有类别列表。 可以更新问题以清除链接的类别并将类别保持为空 在第三个案例中,我面临以下问题,如异常跟踪日志中所述Java 将外键引用设置为null以使用spring boot清除关系,java,spring-boot,spring-rest,many-to-one,Java,Spring Boot,Spring Rest,Many To One,我是spring boot应用程序开发新手,面临以下问题 我正在使用一个应用程序,在该应用程序中,我正在开发要跟踪的问题。每个问题都可以关联到特定类别。但是,将问题与特定类别关联不是强制性的 可以创建问题,而无需将其与任何特定类别关联。 可以更新问题以查找现有类别列表。 可以更新问题以清除链接的类别并将类别保持为空 在第三个案例中,我面临以下问题,如异常跟踪日志中所述 2019-03-02 23:07:56.854 INFO 3984 --- [nio-8080-exec-9] c.a.m.A
2019-03-02 23:07:56.854 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.controller.IssueController : Inside updateIssue() API :: Updating Issue ::: OTPC-1000
2019-03-02 23:07:56.855 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.controller.IssueController : updateIssue() :: Logging input parameters passed for updated!
2019-03-02 23:07:56.856 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.controller.IssueController : Key ::: (component) ==> value ::: ()
2019-03-02 23:07:56.856 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.controller.IssueController : Key ::: (id) ==> value ::: (OTPC-1000)
2019-03-02 23:07:56.859 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.services.IssueServiceImpl : Inside updateIssuebyIssueId() API in IssueServiceImpl ::: OTPC-1000
2019-03-02 23:07:56.860 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.services.IssueServiceImpl : updateIssuebyIssueId() :: Update Query :: update issue i set i.component = ?, i.id = ? where i.id = ?
2019-03-02 23:07:56.868 INFO 3984 --- [nio-8080-exec-9] c.a.m.A.services.IssueServiceImpl : updateIssuebyIssueId() :: Final Update Query with values :: update issue i set i.component = ?, i.id = ? where i.id = ?
Hibernate:
update
issue i
set
i.component = ?,
i.id = ?
where
i.id = ?
2019-03-02 23:07:56.894 WARN 3984 --- [nio-8080-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1452, SQLState: 23000
2019-03-02 23:07:56.894 ERROR 3984 --- [nio-8080-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : Cannot add or update a child row: a foreign key constraint fails (`agilecenterdb`.`issue`, CONSTRAINT `FKnwf3mlopxg840otjaqxjidwbf` FOREIGN KEY (`component`) REFERENCES `issue_component` (`id`))
Exception encountered
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1700)
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:70)
at com.app.mycompany.AgileCenterServices.services.IssueServiceImpl.updateIssuebyIssueId(IssueServiceImpl.java:194)
我用以下方式定义了实体
Issue.java
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.springframework.context.annotation.Scope;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.app.mycompany.AgileCenterServices.audit.Auditable;
@Entity
@Table(name="Issue")
@EntityListeners(AuditingEntityListener.class)
@Scope("session")
public class Issue extends Auditable<String> {
@Id
@GenericGenerator(name = "sequence_issue_id", strategy = "com.app.mycompany.AgileCenterServices.util.IssueIdGenerator",
parameters = @Parameter(name = "ProjectKey", value = "PeopleCenter" ))
@GeneratedValue(generator = "sequence_issue_id")
@Column(unique = true)
private String id;
private String issueType;
private String summary;
@ManyToOne
@JoinColumn (nullable = true, updatable = true, name = "component", referencedColumnName = "id")
private IssueComponent component;
/* getters and setters */
}
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PreRemove;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.context.annotation.Scope;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.app.mycompany.AgileCenterServices.audit.Auditable;
import com.fasterxml.jackson.annotation.JsonBackReference;
@Entity
@Table(name="IssueComponent")
@EntityListeners(AuditingEntityListener.class)
@Scope("session")
public class IssueComponent extends Auditable<String> {
@Id
@GenericGenerator(name = "sequence_issuecomponent_id", strategy = "com.app.mycompany.AgileCenterServices.util.IssueComponentIdGenerator")
@GeneratedValue(generator = "sequence_issuecomponent_id")
@Column(unique = true)
private String id;
private String name;
private String description;
private Integer totalIssues;
@ManyToOne
@JoinColumn (name = "componentLead", referencedColumnName = "username")
private User componentLead;
@ManyToOne
@JoinColumn (name = "project", referencedColumnName = "id")
private Project project;
@Column(nullable = false, name = "active", columnDefinition = "BOOLEAN")
private Boolean active;
@JsonBackReference
@OneToMany(mappedBy="component", cascade = CascadeType.PERSIST)
private Set<Issue> issues;
/* getters & setters */
}
@Override
@Transactional
public int updateIssuebyIssueId(String issueId, Map<String, String> customUpdateQuery)
throws NoResultException, Exception {
logger.info(" Inside updateIssuebyIssueId() API in IssueServiceImpl ::: " + issueId);
int columnsToUpdate = 0;
StringBuilder updateSqlQuery = new StringBuilder("update issue i set ");
for(String key : customUpdateQuery.keySet()) {
if(key != null && (key.equalsIgnoreCase("createdBy"))
|| (key.equalsIgnoreCase("modifiedBy"))) {
continue;
}
String column = key;
if(key != null && key.equalsIgnoreCase("status")) {
// issueStatusUpdated = true;
}
if(key != null && key.equalsIgnoreCase("epicStatus")) {
column = "epic_status";
}
if(key != null && key.equalsIgnoreCase("issueType")) {
column = "issue_type";
}
if(key != null && key.equalsIgnoreCase("dueDate")) {
column = "due_date";
}
if(key != null && key.equalsIgnoreCase("startDate")) {
column = "start_date";
}
if(key != null && key.equalsIgnoreCase("assignedToUser")) {
column = "assigned_to_user";
}
if(key != null && key.equalsIgnoreCase("requestedBy")) {
column = "requested_by";
}
if(columnsToUpdate == 0) {
updateSqlQuery = updateSqlQuery.append("i." + column).append(" = ?");
}
else {
updateSqlQuery = updateSqlQuery.append(", ");
updateSqlQuery = updateSqlQuery.append("i." + column).append(" = ?");
}
columnsToUpdate++;
}
updateSqlQuery.append(" where i.id = ?");
logger.info("updateIssuebyIssueId() :: Update Query :: " + updateSqlQuery);
Query query = entityManager.createNativeQuery(updateSqlQuery.toString());
int index = 1;
int recordsUpdated = 0;
for(String key: customUpdateQuery.keySet()) {
if(key.equalsIgnoreCase("id")) {
continue;
}
**if(customUpdateQuery.get(key) == "") {
logger.info("Setting value to null for key :: " + key);
query.setParameter(index, null);
} else {
query.setParameter(index, customUpdateQuery.get(key));
}**
index++;
}
query.setParameter(index, issueId);
logger.info("updateIssuebyIssueId() :: Final Update Query with values :: " + updateSqlQuery);
try {
entityManager.joinTransaction();
recordsUpdated = query.executeUpdate();
}catch(NoResultException e) {
System.out.println("No records found");
e.printStackTrace();
throw new NoResultException();
}catch (Exception e) {
System.out.println("Exception encountered");
e.printStackTrace();
throw new Exception("Exception encountered");
}
return recordsUpdated;
}
请参考Issue表中的“component”列,该列引用IssueComponent表中的id列请提供db Schema实际代码,我没有看到包含“component=null”的sql字符串。此外,还应该启用SQL输出以有效地传递参数值。最后,您创建SQL查询的方法是不正确的。您不想为此连接字符串(不一定是安全的、不太清晰的和不健壮的)。在您操作JPA实体时,请使用JDBC(preparedStatement)或者更确切地说是JPA。您好,David,谢谢您的快速响应。我一直在调试以验证SQL输出。实际上,您不会看到“component=null”,因为它仅为不直接映射到json输入的列显式设置。当组件实际被调用时,我已经用SQL输出更新了日志。如果我还需要更改,请告诉我。非常感谢大卫。你的见解很有帮助。实际上,没有按照外键引用列的要求传递Null值。非常感谢你的见解。您可以分享一些指针来构建上面提到的SQL更新查询(preparedStatements)。如果它可以帮助您找到问题,那就太好了。PreparedStatements是用于JDBC的(实际上是您编写的本机查询,所以它非常接近)。但是您实际上使用的是JPA,所以您应该更喜欢JPQL或ORM方法
EntityManager.persist()/save()
请提供db schemain实际代码,我没有看到包含“component=null”的sql字符串。此外,还应该启用SQL输出以有效地传递参数值。最后,您创建SQL查询的方法是不正确的。您不想为此连接字符串(不一定是安全的、不太清晰的和不健壮的)。在您操作JPA实体时,请使用JDBC(preparedStatement)或者更确切地说是JPA。您好,David,谢谢您的快速响应。我一直在调试以验证SQL输出。实际上,您不会看到“component=null”,因为它仅为不直接映射到json输入的列显式设置。当组件实际被调用时,我已经用SQL输出更新了日志。如果我还需要更改,请告诉我。非常感谢大卫。你的见解很有帮助。实际上,没有按照外键引用列的要求传递Null值。非常感谢你的见解。您可以分享一些指针来构建上面提到的SQL更新查询(preparedStatements)。如果它可以帮助您找到问题,那就太好了。PreparedStatements是用于JDBC的(实际上是您编写的本机查询,所以它非常接近)。但实际上您使用的是JPA,所以您应该更喜欢JPQL或ORM方法EntityManager.persist()/save()
mysql> desc issue;
+--------------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------------+--------------+------+-----+---------+-------+
| id | varchar(255) | NO | PRI | NULL | |
| created_by | varchar(255) | YES | | NULL | |
| created_date | datetime | YES | | NULL | |
| last_modified_by | varchar(255) | YES | | NULL | |
| last_modified_date | datetime | YES | | NULL | |
| customer | varchar(255) | YES | | NULL | |
| customer_support_ticket_number | varchar(255) | YES | | NULL | |
| description | varchar(255) | YES | | NULL | |
| discovery | varchar(255) | YES | | NULL | |
| due_date | datetime | YES | | NULL | |
| priority | varchar(255) | YES | | NULL | |
| start_date | datetime | YES | | NULL | |
| status | varchar(255) | YES | | NULL | |
| summary | varchar(255) | YES | | NULL | |
| team | varchar(255) | YES | | NULL | |
| component | varchar(255) | YES | MUL | NULL | |
+--------------------------------+--------------+------+-----+---------+-------+
mysql> desc issue_component;
+--------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| id | varchar(255) | NO | PRI | NULL | |
| created_by | varchar(255) | YES | | NULL | |
| created_date | datetime | YES | | NULL | |
| last_modified_by | varchar(255) | YES | | NULL | |
| last_modified_date | datetime | YES | | NULL | |
| active | tinyint(1) | NO | | NULL | |
| description | varchar(255) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| total_issues | int(11) | YES | | NULL | |
| component_lead | varchar(255) | YES | MUL | NULL | |
| project | varchar(255) | YES | MUL | NULL | |
+--------------------+--------------+------+-----+---------+-------+