设置属性时,JPA执行INSERT-Statement

时间:2019-03-17 10:15:58

标签: java jpa java-ee

我有这两个实体

@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。在这种情况下,代码可以正常工作。问题:

谁能解释我为什么会这样?

0 个答案:

没有答案