2013-07-02 57 views
2

我有一個自動生成的ID作爲主鍵和一個到多個映射到電話表的學生表。Hibernate的StackOverflowError保存

我的電話表具有帶電話號碼的複合主鍵PhonePK和學生表的外鍵ID。

如果我只是做student.setPhones而不是做phonepk.setStudent,它抱怨的ID不能爲空。所以我設置了student.setPhones和phonePk.setStudent。但是現在我得到了toString上的一個stackoverflow錯誤。

我真的不喜歡在兩種方式上設置它,但不知道如何解決id不能爲null的錯誤。我一直在問很多人,但他們無能爲力。有人可以看看嗎?

Student.java

import java.io.Serializable; 
import java.util.Set; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.OneToMany; 

@Entity 
@SuppressWarnings("serial") 
public class Student implements Serializable { 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private int id; 

private String fName; 

private String lName; 

private String mName; 

@OneToMany(cascade = CascadeType.ALL) 
@JoinColumn(name = "id") 
private Set<Phone> phones; 

/** 
* @return the fName 
*/ 
public String getfName() { 
    return fName; 
} 

/** 
* @return the id 
*/ 
public int getId() { 
    return id; 
} 

/** 
* @return the lName 
*/ 
public String getlName() { 
    return lName; 
} 

/** 
* @return the mName 
*/ 
public String getmName() { 
    return mName; 
} 

/** 
* @return the phones 
*/ 
public Set<Phone> getPhones() { 
    return phones; 
} 

/** 
* @param fName 
*   the fName to set 
*/ 
public void setfName(final String fName) { 
    this.fName = fName; 
} 

/** 
* @param id 
*   the id to set 
*/ 
public void setId(final int id) { 
    this.id = id; 
} 

/** 
* @param lName 
*   the lName to set 
*/ 
public void setlName(final String lName) { 
    this.lName = lName; 
} 

/** 
* @param mName 
*   the mName to set 
*/ 
public void setmName(final String mName) { 
    this.mName = mName; 
} 

/** 
* @param phones 
*   the phones to set 
*/ 
public void setPhones(final Set<Phone> phones) { 
    this.phones = phones; 
} 

/** 
* {@inheritDoc} 
*/ 
@Override 
public String toString() { 
    return String.format("Student [id=%s, fname=%s, lname=%s, mname=%s, phones=%s]",  
id, 
     fName, lName, mName, phones); 
} 

} 

Phone.java

import java.io.Serializable; 

import javax.persistence.EmbeddedId; 
import javax.persistence.Entity; 

@Entity 
@SuppressWarnings("serial") 
public class Phone implements Serializable { 

@EmbeddedId 
private PhonePK PK; 

private String color; 

/** 
* @return the color 
*/ 
public String getColor() { 
    return color; 
} 

public PhonePK getPK() { 
    return PK; 
} 

/** 
* @param color 
*   the color to set 
*/ 
public void setColor(final String color) { 
    this.color = color; 
} 

public void setPK(final PhonePK pK) { 
    PK = pK; 
} 

/** 
* {@inheritDoc} 
*/ 
@Override 
public String toString() { 
    return String.format("Phone [PK=%s, color=%s]", PK, color); 
} 

} 

PhonePK.java

import java.io.Serializable; 

import javax.persistence.Embeddable; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 

@Embeddable 
@SuppressWarnings({ "serial" }) 
public class PhonePK implements Serializable { 

@ManyToOne 
@JoinColumn(name = "id", insertable = false, updatable = false) 
private Student student; 

private String phoneNumber; 

public String getPhoneNumber() { 
    return phoneNumber; 
} 

public Student getStudent() { 
    return student; 
} 

public void setPhoneNumber(final String phoneNumber) { 
    this.phoneNumber = phoneNumber; 
} 

public void setStudent(final Student student) { 
    this.student = student; 
} 

/** 
* {@inheritDoc} 
*/ 
@Override 
public String toString() { 
    return String.format("PhonePK [student=%s, phoneNumber=%s]", student, phoneNumber); 
} 

} 

Main.java

import java.util.LinkedHashSet; 
import java.util.Set; 

import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.Transaction; 
import org.hibernate.cfg.Configuration; 

public class Main { 

public static void main(final String args[]) { 

    Configuration configuration = new Configuration(); 
    Transaction transaction = null; 

    configuration.addAnnotatedClass(Student.class); 
    configuration.addAnnotatedClass(Phone.class); 
    configuration.configure("hibernate.cfg.xml"); 
    SessionFactory sessionFactory = configuration.buildSessionFactory(); 
    Session session = sessionFactory.openSession(); 

    Student student = new Student(); 
    student.setfName("Bob"); 
    student.setlName("Buster"); 

    Set<Phone> phones = new LinkedHashSet<Phone>(); 
    Phone phone = new Phone(); 
    phone.setColor("Black"); 
    PhonePK phonePK = new PhonePK(); 
    phonePK.setPhoneNumber("1111111111"); 
    phonePK.setStudent(student); // Do not do this? But won't work (id cannot be null 
    error) if 
           // commented out?? 
    phone.setPK(phonePK); 
    phones.add(phone); 

    student.setPhones(phones); 

    try { 
     transaction = session.beginTransaction(); 
     System.out.println(student.toString()); // stackoverflow error! 
     session.save(student); 
     transaction.commit(); 
    } catch (HibernateException e) { 
     transaction.rollback(); 
     e.printStackTrace(); 
    } finally { 
     session.close(); 
    } 

} 
} 

回答

2

它正在發生,因爲你的方式定義的toString()方法

學生toString()被調用手機的toString()這是調用PhonePK的toString()而這又是調用學生toString()造成無限循環


讓我們看看它是如何在具體的方式發生

學生toString()它因爲phones實例變量。它將通過每個電話和呼叫電話toString()

public String toString() { 
    return String.format("Student [id=%s, fname=%s, lname=%s, mname=%s, phones=%s]",  
id, 
     fName, lName, mName, phones); 
} 



迭代 在電話toString()因爲它的PK實例變量,它將調用PhonePK toString()

public String toString() { 
    return String.format("Phone [PK=%s, color=%s]", PK, color); 
} 



在PhonePK toString()因爲它phoneNumber實例變量。它會調用電話toString()

public String toString() { 
    return String.format("PhonePK [student=%s, phoneNumber=%s]", student, phoneNumber); 
} 
+0

好吧,謝謝你..我糾正它。從PhonePK toString方法中刪除學生實例變量。但是有沒有辦法可以一起避免循環引用?我不想做student.setPhones和phone.setStudent兩者。不應該冬眠照顧這個? – nomula

相關問題