saveorupdate()不会在hibernate中更新集合(列表)一对多映射

时间:2013-12-17 15:02:03

标签: java hibernate hibernate-mapping hibernate-onetomany

班级Student

public class Student {

private Long id;
private String name;
private String className;
private List<Phone> phones;
    // getter setter
 }

班级Phone

public class Phone {

private Long id;
private String number;
   //getter setter
     }

- &GT; mappping file Student.hbm.xml

     <id name="id" type="long" column="id">
        <generator class="native" />
    </id>

    <property name="name" column="name" type="string" />

    <property name="className" column="class_name" type="string" />

    <list name="phones" cascade="all-delete-orphan">
        <key column="student_id"/>
        <list-index column="idx" />
        <one-to-many class="Phone" />
    </list>

- &GT;映射文件Phone.hbm.xml

    <id name="id" type="long" column="id">
        <generator class="native" />
    </id>

    <property name="number" column="number" type="string" />

当我尝试更新电话号码(列表)时,前一个条目不会被删除,但idx(列表索引)和外键为空,新条目用正确的idx和外键标记! !其他数据(不是列表)完全更新。在这里,我从数据库中获取类对象,修改它并将对象传递给saveorupdate(),但没有帮助。一直在尝试这么久。

要读取和更新的代码:

      private void readAndUpdateStudent() {
       Student student = null;
       Session session = HibernateUtil.getSessionFactory().openSession();
       String name = "John";
         try {

        String queryString = "from Student student where student.name =:name";
        Query query = session.createQuery(queryString);
        query.setString("name", name);
        student = (Student) query.uniqueResult();
        System.out.println(student.getName());
        student.setName("Mary");
        List<Phone> phones = new ArrayList<Phone>();
        phones.add(new Phone("555555")); //here if I SET rather adding, the already existing values, update is done accordingly 
        phones.add(new Phone("789789"));//but when I use the list as a string type(instead of Phone Type), adding a new 0bject deletes the previous 
        student.setPhones(phones);//entries and adds new list on its own  but not in the case of user defined type.

    } catch (Exception e) {     
        e.printStackTrace();
        if (session != null) {

            session.close();

        }

    }finally{

        session.close();
        updateStudent(student);
    }

}
private void updateStudent(Student student) {

    Session session = HibernateUtil.getSessionFactory().openSession();
    Transaction tx = null;

    try {
        tx = session.beginTransaction();
        session.saveOrUpdate(student);
        tx.commit();
    } catch (HibernateException e) {
        if (tx != null)
            tx.rollback();
        e.printStackTrace();
    } finally {
        session.close();
    }
}

enter image description here

2 个答案:

答案 0 :(得分:1)

我注意到现在有点老了,但是FWIW,另一个答案是对的,你不应该在hibernate检索的持久化实体上设置一个新的集合,因为这会像你的情况一样创建孤儿。 / p>

Hibernate代理实体,以便它可以管理实体属性的数据库更新(哪些字段已更改等)。因此,当您检索实体并设置新列表时,hibernate将无法跟踪该列表中的更改。因此,您应该按指出更新现有List,以便在更新时删除孤立。您也可以使用clear()。

List<Phone> phones = student.getPhones();
phones.clear();
phones.add(new Phone("555555"));
phones.add(new Phone("789789"));
session.saveOrUpdate(student);

如果你想避免重复,请尝试Set而不是列表,并在Phone类上实现hashCode()和equals(),例如,检查phone.number上的检查相等性是否有意义。

希望这会有所帮助:)

答案 1 :(得分:0)

如果您想更新手机列表,则不应该

    List<Phone> phones = new ArrayList<Phone>();
    phones.add(new Phone("555555"));
    phones.add(new Phone("789789"));
    student.setPhones(phones);

以上代码不会更新手机列表,但会创建一个全新的手机。 要更新手机列表,您应检索旧列表并更新其条目

    List<Phone> phones = student.getPhones();
    phones.get(0).setNumber("666666");
    phones.get(1).setNumber("888888");
    session.saveOrUpdate(student);