我有这两个实体
@Entity
public class Athlete implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer athleteId;
private String firstName;
private String lastName;
private Long phoneNumber;
@Enumerated(EnumType.STRING)
private Gender gender;
@OneToOne(mappedBy="athlete")
private Closet closet;
还有这个:
@Entity
public class Closet implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer closetId;
private boolean isOccupied=false;
private boolean isBroken=false;
@Enumerated(EnumType.STRING)
private Rank closetRank=Rank.REGULAR;
@OneToOne (cascade= {CascadeType.PERSIST,CascadeType.REMOVE})
@JoinColumn(name="athleteId")
private Athlete athlete;
@Temporal(TemporalType.TIMESTAMP)
private Date reservationStarted;
@Temporal(TemporalType.TIMESTAMP)
private Date reservationEnded;
@Enumerated(EnumType.STRING)
private Gender gender;
我并没有放置所有setter和getters方法,它们在我的代码中很常见。
在Bean类中,我对该方法进行了编码:
@Stateless
@LocalBean
public class ClosetService implements ClosetServiceLocal {
@PersistenceContext(unitName="SportClosets")
EntityManager entityManager;
public Closet addAthleteToCloset(Athlete singleAthlete, String closetId) {
//Find Closet
CriteriaBuilder builder=entityManager.getCriteriaBuilder();
CriteriaQuery<Closet> queryCloset=
builder.createQuery(Closet.class);
Root<Closet> rootPassenger=queryCloset.from(Closet.class);
queryCloset.select(rootPassenger).
where(builder.equal(rootPassenger.get("closetId").
as(Integer.class),closetId));
Closet singleCloset=
entityManager.createQuery(queryCloset).getSingleResult();
singleCloset.setAthlete(singleAthlete);
return singleCloset;
}
这就是问题所在。
当我继续创建对象singleAthlete时,然后将其持久保存,然后将其设置为对象singleCloset中的一个属性,就会出现异常:
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException: Die Anweisung wurde abgebrochen, weil sie in einer für 'ATHLETE' definierten Vorgabe für einen eindeutigen oder Primärschlüssel-Constraint bzw. für einen von 'SQL190317091523970' identifizierten und eindeutigen Index zu einem duplizierten Schlüsselwert geführt hätte.
Error Code: 20000
Call: INSERT INTO ATHLETE (ATHLETEID, FIRSTNAME, GENDER, LASTNAME, PHONENUMBER) VALUES (?, ?, ?, ?, ?)
bind => [5 parameters bound]
Query: InsertObjectQuery(com.models.Athlete@24790911)
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:905)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:967)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:637)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:564)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2093)
at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:309)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:270)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:256)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:405)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:502)
at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:314)
at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:911)
at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:810)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2979)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1892)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1874)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1824)
at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:227)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:194)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:139)
at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4384)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1491)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1581)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3256)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:355)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:158)
... 43 more
Caused by: org.apache.derby.shared.common.error.DerbySQLIntegrityConstraintViolationException: Die Anweisung wurde abgebrochen, weil sie in einer für 'ATHLETE' definierten Vorgabe für einen eindeutigen oder Primärschlüssel-Constraint bzw. für einen von 'SQL190317091523970' identifizierten und eindeutigen Index zu einem duplizierten Schlüsselwert geführt hätte.
at org.apache.derby.client.am.SQLExceptionFactory.getSQLException(Unknown Source)
at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
at org.apache.derby.client.am.ClientPreparedStatement.executeUpdate(Unknown Source)
at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:125)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:895)
... 75 more
Caused by: ERROR 23505: Die Anweisung wurde abgebrochen, weil sie in einer für 'ATHLETE' definierten Vorgabe für einen eindeutigen oder Primärschlüssel-Constraint bzw. für einen von 'SQL190317091523970' identifizierten und eindeutigen Index zu einem duplizierten Schlüsselwert geführt hätte.
at org.apache.derby.client.am.ClientStatement.completeExecute(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown Source)
at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
at org.apache.derby.client.net.StatementReply.readExecute(Unknown Source)
at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown Source)
at org.apache.derby.client.am.ClientPreparedStatement.readExecute(Unknown Source)
at org.apache.derby.client.am.ClientPreparedStatement.flowExecute(Unknown Source)
at org.apache.derby.client.am.ClientPreparedStatement.executeUpdateX(Unknown Source)
... 78 more
]]
(对不起,德语部分,显然我使用的是德比德文版)
这是我的操作方式:
package com.servlets;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.Beans.AthleteService;
import com.Beans.ClosetService;
import com.models.Athlete;
import com.models.Closet;
import com.models.Gender;
import com.sun.xml.ws.util.StringUtils;
/**
* Servlet implementation class ManageCloset
*/
@WebServlet("/ManageClosets")
public class ManageCloset extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
ClosetService closetService;
@EJB
AthleteService athleteService;
/**
* @see HttpServlet#HttpServlet()
*/
public ManageCloset() {
super();
// TODO Auto-generated constructor stub
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher view =request.getRequestDispatcher("WEB-INF/closetEntryPanel.jsp");
String closetId="";
String athleteID="";
String firstName="";
String lastName="";
String phoneNumber="";
Gender gender;
Map<String, String[]> parameterMap=request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()){
if(entry.getKey().contains("ADD_CLOSET_")) {
closetId=entry.getKey().split("_")[2];
}
}
athleteID=request.getParameter("atheteID");
Athlete singleAthlete=null;
if("".equals(athleteID)) {
singleAthlete=new Athlete();
String gdStr=request.getParameter("gender");
gender=Gender.valueOf(gdStr);
singleAthlete.setGender(gender);
firstName=request.getParameter("firstName");
singleAthlete.setFirstName(firstName);
lastName=request.getParameter("lastName");
singleAthlete.setLastName(lastName);
phoneNumber=request.getParameter("phoneNumber");
singleAthlete.setPhoneNumber(Long.parseLong(phoneNumber));
// It just persists the Object with EntityManager like:
// entityManager.persist(singleAthlete);
// return singleAthlete
singleAthlete=athleteService.addAthlete(singleAthlete);
}
closetService.addAthleteToCloset(singleAthlete, closetId);
view.forward(request, response);
}
}
另一方面,当我不持久化Object singleAthlete并仅设置Object singleCloset的属性时,JPA会自动持久化Object singleAthlete。在这种情况下,代码可以正常工作。问题:
谁能解释我为什么会这样?