2015-05-03 147 views
2

過去4小時我正在處理此JPA問題。最後我放棄了,所以我要求你的幫助。到目前爲止,我嘗試了幾乎所有建議的解決方案。JPA:重複輸入主鍵

我嘗試,

1)映射改變(@ManyToOne,@OneToOne,@OneToMany)

2)級聯選項(持續,MERGE,ALL ..)

3)禁用緩存

3)許多其他嘗試,不像1,2和3 spesific。只是希望。 :)

的TestClass

public class testClass { 
public static void main(String[] args) { 

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_482_Project_4_-_PersistencePU"); 
    EntityManager em = emf.createEntityManager(); 
    EntityTransaction tx = em.getTransaction(); 

    File parentFile = new File("cleardata"); 
    File[] allFiles = parentFile.listFiles(); 
    File myFile; 
    int k = 1; 

    for(int f =0; f<allFiles.length; f++){ 
    try { 
     myFile=allFiles[f]; 
     BufferedReader br = new BufferedReader(new FileReader(myFile)); 

     String tempDate = br.readLine(); 
     tempDate = tempDate.substring(17); 
     String[] tempDateArr = tempDate.split(" "); 
     int day = Integer.parseInt(tempDateArr[0]); 
     int month = Integer.parseInt(tempDateArr[1]); 
     int year = Integer.parseInt(tempDateArr[2]); 

     Date leavingDate = new Date(year, month, day); 

     String studentNumber = br.readLine().substring(13); 
     boolean minor = true; 
     if (br.readLine().contains("false")) { 
      minor = false; 
     } 
     Student stu = new Student(studentNumber, leavingDate); 
     stu.setMinorDegree(minor); 

     tx.begin(); 
     em.persist(stu); 
     tx.commit(); 

     String currentLine; 
     Slot s; 
     Course c; 
     SlotAndCourse sc; 
     int semester = 0; 
     String courseCode = ""; 
     String slotName = ""; 
     int credit = 0; 
     String termTaken = ""; 
     int yearTaken = 0; 
     String grade = ""; 
     boolean semesterSet = false; 
     boolean courseSet = false; 
     boolean gradesSet = false; 

     int count = 0; 


     while ((currentLine = br.readLine()) != null) { 
      String[] arr = currentLine.split(" "); 

      if (arr[0].equals("semester")) { 
       semester = Integer.parseInt(arr[1]); 
       semesterSet = true; 
      } else if (arr[0].matches("^([0-9]+[a-zA-Z]+|[a-zA-Z]+[0-9]+)[0-9a-zA-Z]*$")) { // contains both latters and digits CS112 
       courseCode = arr[0]; 
       slotName = arr[1]; 
       credit = Integer.parseInt(arr[2]); 
       courseSet = true; 
      } else if (arr[0].equals("numberofattempts")) { 
       int n = Integer.parseInt(arr[1]); 
       for (int i = 0; i < n; i++) { 
        currentLine = br.readLine(); 
        System.out.println(currentLine); 
        arr = currentLine.split(" "); 
        yearTaken = Integer.parseInt(arr[0]); 
        termTaken = arr[1]; 
        grade = arr[2]; 
       } 
       gradesSet = true; 
      } 

      if (gradesSet && courseSet && semesterSet) { 
       s = new Slot(); 
       c = new Course(courseCode); 

       s.setCredit(credit); 
       s.setSemester(semester); 
       s.setSlotName(slotName); 
       s.setSlotCode("" + k); 

       c.setCourseCode(courseCode); 

       sc = new SlotAndCourse(s,c,yearTaken,termTaken); 
       sc.setCourse(c); 
       sc.setSlot(s); 
       sc.setGrade(grade); 

       tx.begin(); 

       em.clear(); // just a try, but didn't work 
       em.persist(sc); 
       tx.commit();     

       courseSet = false; 
       semesterSet = false; 
       gradesSet = false; 
       k++; 
      } 

     } 

    } catch (Exception ex) { 
     System.out.println(ex.toString()); 
     ex.printStackTrace(); 
    } 
    } 
    em.close(); 
} 

} 

學生班級

@Entity 
@Cacheable(false) 
public class Student implements Serializable { 

@Id 
private String studentNumber; 

@Temporal(TemporalType.DATE) 
private Date leavIngDate; 
private boolean mInorDegree; 

public Student() { 
} 

public Student(String studentNumber, Date leavingDate) { 
    this.studentNumber = studentNumber; 
    this.leavIngDate = leavingDate; 
} 

@Override 
public boolean equals(Object obj) { 
    if (!(obj instanceof Slot)) { 
     return false; 
    } 
    Student other = (Student) obj; 
    if ((this.studentNumber == null && other.studentNumber != null) || (this.studentNumber != null && !this.studentNumber.equals(other.studentNumber))) { 
     return false; 
    } 
    return true; 
} 

@Override 
public int hashCode() { 
    int hash = 0; 
    hash += (studentNumber != null ? studentNumber.hashCode() : 0); 
    return hash; 
} 

    // setters and getters 

課程班

@Entity 
    @Cacheable(false) 
    public class Course implements Serializable { 

    @Id 
    private String courseCode; 

public Course() { 
} 

public Course(String courseCode) { 
    this.courseCode = courseCode; 
} 

@Override 
public boolean equals(Object obj) { 
    if (!(obj instanceof Course)) { 
     return false; 
    } 
    Course other = (Course) obj; 
    if ((this.courseCode == null && other.courseCode != null) || (this.courseCode != null && !this.courseCode.equals(other.courseCode))) { 
     return false; 
    } 
    return true; 
} 

@Override 
public int hashCode() { 
    int hash = 0; 
    hash += (courseCode != null ? courseCode.hashCode() : 0); 
    return hash; 
} 

    //setters and getters 

時隙等級

@Entity 
    @Cacheable(false) 
    public class Slot implements Serializable { 
    @Id 
private String slotCode; 
private String slotName; 
private int credIt; 
private int semester; 

public Slot() { 
} 

public Slot(String slotCode, String slotName) { 
    this.slotCode = slotCode; 
    this.slotName = slotName; 
} 

@Override 
public boolean equals(Object obj) { 
    if (!(obj instanceof Slot)) { 
     return false; 
    } 
    Slot other = (Slot) obj; 
    if ((this.slotCode == null && other.slotCode != null) || (this.slotCode != null && !this.slotCode.equals(other.slotCode))) { 
     return false; 
    } 
    return true; 
} 

@Override 
public int hashCode() { 
    int hash = 0; 
    hash += (slotCode != null ? slotCode.hashCode() : 0); 
    return hash; 

    //setters getters 

SlotAndCourse類

@Entity 
@Cacheable(false) 
public class SlotAndCourse implements Serializable { 
@EmbeddedId 
protected SlotAndCoursePK slotAndCoursePK; 

@JoinColumn(name = "SLOTCODE", referencedColumnName = "SLOTCODE", insertable = false, updatable = false) 
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.ALL}) 
private Slot slot; 

@JoinColumn(name = "COURSECODE", referencedColumnName = "COURSECODE", insertable = false, updatable = false) 
@ManyToOne(cascade = CascadeType.PERSIST) 
private Course course; 

private String grade; 

public SlotAndCourse() { 
} 

public SlotAndCourse(SlotAndCoursePK slotAndCoursePK) { 
    this.slotAndCoursePK = slotAndCoursePK; 
} 

public SlotAndCourse(String slotCode, String courseCode, int yearTaken, String termTaken) { 
    this.slotAndCoursePK = new SlotAndCoursePK(slotCode, courseCode, yearTaken, termTaken); 
} 
public SlotAndCourse(Slot s, Course c, int yearTaken, String termTaken) { 
    this.slot = s; 
    this.course = c; 
    this.slotAndCoursePK = new SlotAndCoursePK(s.getSlotCode(), c.getCourseCode(),yearTaken,termTaken); 
} 

@Override 
public boolean equals(Object obj) { 
    if(obj instanceof SlotAndCourse){ 
     SlotAndCourse arg = (SlotAndCourse)obj; 
     return this.slotAndCoursePK.equals(arg.slotAndCoursePK); 
    } 
    else if(obj instanceof SlotAndCoursePK){ 
     SlotAndCoursePK arg = (SlotAndCoursePK)obj; 
     return this.slotAndCoursePK.equals(arg); 
    } 
    return false; 
} 

@Override 
public int hashCode() { 
    int hash = 0; 
    hash += (slotAndCoursePK != null ? slotAndCoursePK.hashCode() : 0); 
    return hash; 
} 

SlontAndCoursePK類

@Embeddable 
public class SlotAndCoursePK implements Serializable{ 

protected String slotCode; 
protected String courseCode; 
protected int yearTaken; 
protected String termTaken; 

public SlotAndCoursePK() { 
} 

public SlotAndCoursePK(String slotCode, String courseCode, int yearTaken, String termTaken) { 
    this.slotCode = slotCode; 
    this.courseCode = courseCode; 
    this.yearTaken = yearTaken; 
    this.termTaken = termTaken; 
} 

@Override 
public int hashCode() { 
    int hash = 0; 
    hash += (slotCode != null ? slotCode.hashCode() : 0); 
    hash += (courseCode != null ? courseCode.hashCode() : 0); 
    return hash; 
} 

@Override 
public boolean equals(Object object) { 
    // TODO: Warning - this method won't work in the case the id fields are not set 
    if (!(object instanceof SlotAndCoursePK)) { 
     return false; 
    } 
    SlotAndCoursePK other = (SlotAndCoursePK) object; 
    if ((this.slotCode == null && other.slotCode != null) || (this.slotCode != null && !this.slotCode.equals(other.slotCode))) { 
     return false; 
    } 
    if ((this.courseCode == null && other.courseCode != null) || (this.courseCode != null && !this.courseCode.equals(other.courseCode))) { 
     return false; 
    } 
    return true; 
} 

// setters and getters 

我覺得應對和粘貼在這裏所有的代碼那麼糟糕。我希望有人能幫助我瞭解我失蹤的事情。 testClass的第一部分是從現有結構良好的文本文件中讀取數據並填充相關的數據字段。

當我運行調試時會發生什麼; 首先一切都很好,它將學生,課程,slotAndCourses添加到數據庫按預期,但是當一個slotAndCourse實例與現有的數據庫中的courseCode創建和特林持久(不知道它是否是正確的詞)數據庫它給了我重複在課程表中的主鍵項目。

錯誤看起來是這樣的:

javax.persistence.RollbackException:異常[的EclipseLink-4002](Eclipse持久服務 - 2.5.2.v20140319-9ad6abd):org.eclipse.persistence.exceptions.DatabaseException javax.persistence.RollbackException:異常[EclipseLink-4002](Eclipse持久性服務 - 2.5.2.v20140319-9ad6abd):org.eclipse.persistence.exceptions.DatabaseException 內部異常:com.mysql.jdbc.exceptions.jdbc4。 MySQLIntegrityConstraintViolationException:重複項'cse110'爲'PRIMARY'鍵' 內部異常:com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationEx ception:重複鍵'cse110'鍵'PRIMARY' 錯誤代碼:1062 錯誤代碼:1062 調用:INSERT INTO COURSE(COURSECODE)VALUES(?) 調用:INSERT INTO COURSE(COURSECODE)VALUES(?)

+1

現在我更好地瞭解你在做什麼,刪除我的答案。它與你的問題沒有關係,所以我將發表評論,如果變量聲明在何處,而不是在沒有其他變量使用的更高範圍中,那麼讀取代碼會更容易。在你擁有它的形式中,讀者只需要閱讀每個變量的所有內容,看看它是否在其他地方使用。更重要的是,你可能會這樣找到自己的問題。 –

+1

開始之前數據庫是否爲空? – gfelisberto

+0

持久性設置設置爲「拖放和創建」,因此每次首次刪除所有模式並重新創建。這只是我現在的一個模板,它有點混亂。我會盡量讓它更容易閱讀:) – user2949556

回答

0

我的猜測是cleardata是一個包含文本文件的目錄。 cleardata目錄中的每個文件都包含單個學生的數據。

我想很多學生可以選擇一門課程,所以你不應該在每次在文本文件中找到它的時候創建一門課程。

而不是c = new Course(courseCode);你應該搜索數據庫,看看是否有保存的課程版本。類似的事情可能會有所幫助(我沒有測試此代碼):

public Course findOrCreateCourse(String courseCode) { 
    Course course = em.find(Course.class, courseCode); 
    if (course == null) 
     course = new Course(courseCode); 
    } 
    return course; 
} 

您可能與其他實體有同樣的問題。

+0

試圖檢查數據庫是否存在與該課程相關的課程否。我想知道它會工作,但我無法完成工作。我會再試一次,因爲它很有意義。你的猜測完全正確。我會盡快嘗試並儘快分享結果。謝謝。 – user2949556

+0

已更新代碼更簡單 - 您可以使用'find',因爲'courseCode'是主鍵。 –

+0

我嘗試了你所說的,它沒有奏效,或者我沒有使它工作。有一部分我不明白。根據這個解決方案,它說,如果您想包含在SlotAndCourse對象中的課程存在於數據庫(在課程表),請不要創建該對象。所以這意味着我不能通過courseCode ='CSE101'向我的SlotAndCourse表添加多行。我嘗試用圖像解釋我想說的話。希望我能解釋我想說的。再次感謝您的考慮。圖片鏈接:[鏈接] http://oi59.tinypic.com/vo7b83.jpg – user2949556

0

今天我終於找到了解決我的問題的方法。以下是任何需要它的人的更新代碼。我發現的主要問題是我沒有單獨堅持Course和Slot對象。我在想,堅持組合SlotAndCourse對象還要插入Course和Slot對象。我的觀察是,如果他們三個(課程,老虎機,CourseAndSlot)堅持在一起,那麼情況會變得更好。我認爲關係是正確設置的。我可能錯了一些概念,但我的代碼現在可以正常工作!

謝謝大家。

我也試圖讓我的代碼更易於閱讀:

的TestClass

public class testClass { 

static EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_482_Project_4_-_PersistencePU"); 
static EntityManager em = emf.createEntityManager(); 
static EntityTransaction tx = em.getTransaction(); 

public static void main(String[] args) { 

    // File related variables 
    File parentFile = new File("cleardata"); 
    File[] allFiles = parentFile.listFiles(); 
    File myFile; 
    BufferedReader br; 
    String currentLine; 

    // Student object and its variables 
    Student stu; 
    Date leavingDate; 
    String studentNumber; 
    boolean minor; 

    // Object declerations 
    Slot s; 
    Course c; 
    SlotAndCourse sc; 

    // datafields of objects 
    int semester = 0; 
    String courseCode = ""; 
    String slotName = ""; 
    int credit = 0; 
    String termTaken = ""; 
    int yearTaken = 0; 
    String grade = ""; 
    String slotCode = ""; 

    // to ensure if every related field is set or not 
    boolean semesterSet = false; 
    boolean courseSet = false; 
    boolean gradesSet = false; 

    for (int f = 0; f < allFiles.length; f++) {  // travesre through files in directory 
     try { 
      myFile = allFiles[f]; 
      br = new BufferedReader(new FileReader(myFile)); 

      String tempDate = br.readLine(); 
      tempDate = tempDate.substring(17); 
      String[] tempDateArr = tempDate.split(" "); 
      int day = Integer.parseInt(tempDateArr[0]); 
      int month = Integer.parseInt(tempDateArr[1]); 
      int year = Integer.parseInt(tempDateArr[2]); 

      leavingDate = new Date(year, month, day); 
      studentNumber = br.readLine().substring(13); 

      minor = true; 
      if (br.readLine().contains("false")) { 
       minor = false; 
      } 
      stu = new Student(studentNumber, leavingDate); 
      stu.setMinorDegree(minor); 
      em.persist(stu); 

      while ((currentLine = br.readLine()) != null) { 
       String[] arr = currentLine.split(" "); 

       if (arr[0].equals("semester")) { 
        semester = Integer.parseInt(arr[1]); 
        semesterSet = true; 
       } else if (arr[0].matches("^([0-9]+[a-zA-Z]+|[a-zA-Z]+[0-9]+)[0-9a-zA-Z]*$")) { // contains both latters and digits CS112 
        slotCode = arr[0]; 
        slotName = arr[1]; 
        credit = Integer.parseInt(arr[2]); 
        courseSet = true; 
       } else if (arr[0].equals("numberofattempts")) { 
        int n = Integer.parseInt(arr[1]); 
        for (int i = 0; i < n; i++) { 
         currentLine = br.readLine(); 
         arr = currentLine.split(" "); 
         yearTaken = Integer.parseInt(arr[0]); 
         termTaken = arr[1]; 
         grade = arr[2]; 
         courseCode = arr[3]; 
         gradesSet = true; 

         if (gradesSet && courseSet && semesterSet) { 

          tx.begin(); 

          s = findOrCreateSlot(slotCode, slotName); 
          c = findOrCreateCourse(courseCode); 

          s.setCredit(credit); 
          s.setSemester(semester); 
          s.setSlotName(slotName); 
          s.setSlotCode(slotCode); 

          sc = findOrCreateSlotAndCourse(s, c, yearTaken, termTaken); 
          sc.setCourse(c); 
          sc.setSlot(s); 
          sc.setGrade(grade); 

          em.persist(s); 
          em.persist(c); 
          em.persist(sc); 
          tx.commit(); 

          courseSet = false; 
          semesterSet = false; 
          gradesSet = false; 
         } 
        } 
       } 
      } 
     } catch (Exception ex) { 
      System.out.println(ex.toString()); 
      ex.printStackTrace(); 
     } 
    } 
    em.close(); 
} 

public static SlotAndCourse findOrCreateSlotAndCourse(Slot s, Course c, int yearTaken, String termTaken) { 
    SlotAndCoursePK pk = new SlotAndCoursePK(s.getSlotCode(), c.getCourseCode(), yearTaken, termTaken); 
    SlotAndCourse slotandcourse = em.find(SlotAndCourse.class, pk); 
    if (slotandcourse == null) { 
     slotandcourse = new SlotAndCourse(s, c, yearTaken, termTaken); 
    } 
    return slotandcourse; 
} 

public static Course findOrCreateCourse(String courseCode) { 
    Course course = em.find(Course.class, courseCode); 
    if (course == null) { 
     course = new Course(courseCode); 
    } 
    return course; 
} 

public static Slot findOrCreateSlot(String slotCode, String slotName) { 
    Slot slot = em.find(Slot.class, slotCode); 
    if (slot == null) { 
     slot = new Slot(slotCode, slotName); 
    } 

    return slot; 
} 

}

+0

這只是歸結爲問題代碼總是創建一個新的課程/插槽和調用堅持它,而這段代碼檢查,看看課程/ slot已經存在,並使用現有的實例。如果存在,持續調用是無操作的,並且沒有理由明確地調用槽/課程實例上的em.persist,而不是調用em.persist(slotandcourse)並讓持續調用級聯。如果您切換到使用em.merge而不是persist,那麼問題代碼也可能工作得很好,因爲如果實例存在或不存在,JPA會解決問題。 – Chris