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

5

class 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
     }

-> 映射文件 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>

-> 映射文件 Phone.hbm.xml
    <id name="id" type="long" column="id">
        <generator class="native" />
    </id>

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

当我尝试更新电话号码(一个列表)时,之前的条目并没有被删除,但是索引和外键都变成了null,并且新添加的条目标记有正确的索引和外键!其他数据(不是列表)都可以很好地更新。我从数据库中获取类对象,修改它并将对象传递给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


我正在使用setter方法将新列表设置到其中,例如student.setPhones(phones),其中phones是新列表。 - gursahib.singh.sahni
@anonymous 展示一下你更新电话的代码。 - RAS
@RaffaeleRossi 先生,刚才我改变了列表数据而不是创建新的列表或添加新的列表对象,Hibernate会相应地删除和更新它们,但当我添加新的列表或创建新的对象时,它重复了同样的故事。希望我表达清楚了。 - gursahib.singh.sahni
刚才我把电话类型改成了字符串列表,Hibernate自己管理所有的删除和更新操作,但是当列表是用户定义类型时,我必须自己更新和删除。为什么会这样? - gursahib.singh.sahni
@anonymous 我无法理解你的问题。你能否展示一下你的代码业务逻辑? - RAS
显示剩余2条评论
2个回答

2
我注意到这篇文章有点老了,但是其他答案是正确的。在Hibernate中,您不应该为已检索到的持久实体设置新集合,因为这样会创建孤儿节点,就像在您的情况下一样。
Hibernate使用代理来管理对数据库的更新(哪些字段已更改等),以便于实体属性。因此,当您检索实体并设置新列表时,Hibernate失去了跟踪先前列表中内容更改的能力。因此,应该像指出的那样更新现有列表,以便在更新时删除孤立的节点。您还可以使用clear()方法。
List<Phone> phones = student.getPhones();
phones.clear();
phones.add(new Phone("555555"));
phones.add(new Phone("789789"));
session.saveOrUpdate(student);

如果您想避免重复,请尝试使用Set而不是List,并在Phone类上实现hashCode()和equals()方法。例如,检查phone.number的相等性可能是有意义的。
希望这可以帮助您 :)

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);

但是当我使用内置的列表类型时,Hibernate会自动处理所有的删除和更新。那么用户定义的数据类型有什么问题吗?我必须手动完成所有这些吗? - gursahib.singh.sahni
区别在于Phone是一个实体,而String只是一种原始类型,因此它们的处理方式不同。 - Raffaele Rossi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接