Hibernate良好的练习,懒惰/渴望加载和保存/删除孩子(帮助我Hibernate sensei)

时间:2016-10-05 10:55:01

标签: java hibernate

所以,我发现自己对Hibernate有很大的反响。当我开始开发我的Web应用程序时,我在所有地方使用“急切”加载,以便我可以轻松访问孩子,父母等。

过了一会儿,我遇到了第一个问题 - 重新保存已删除的对象。多个stackoverflow线程建议我应该从它所在的所有集合中删除该对象。阅读这些建议使我的“蜘蛛感觉”发痒,因为我的关系不是很简单,我不得不迭代多个对象,这使得我的代码看起来很像丑陋,让我想知道这是不是最好的方法。

例如,删除Employee时(在某种意义上,User可以作为多个不同的Employe)属于User。假设员工可以将反馈留给Party,因此Employee可以有多个反馈,Party可以有多个反馈。此外,Employee和Party都属于某种父对象,比如说一个组织。基本上,我们有:

class User {
  // Has many
  Set<Employee> employees;
  // Has many
  Set<Organization> organizations;
  // Has many through employees
  Set<Organization> associatedOrganizations;
}

class Employee {
  // Belongs to
  User user;
  // Belongs to
  Organization organization;
  // Has many
  Set<Feedback> feedbacks;
}

class Organization {
  // Belongs to
  User user;
  // Has many
  Set<Employee> employees;
  // Has many
  Set<Party> parties;
}

class Party {
  // Belongs to
  Organization organization;
  // Has many
  Set<Feedback> feedbacks;
}

class Feedback {
  // Belongs to
  Party party;
  // Belongs to
  Employee employee;
}

这是我在删除员工时最终得到的结果:

// First remove feedbacks related to employee
Iterator<Feedback> iter = employee.getFeedbacks().iterator();
while (iter.hasNext()) {
  Feedback feedback = iter.next();
  iter.remove();
  feedback.getParty().getFeedbacks().remove(feedback);
  session.delete(feedback);
}
session.update(employee);

// Now remove employee from organization
Organization organization = employee.getOrganization();
organization.getEmployees().remove(employee);
session.update(organization);

根据我的定义,这是丑陋的。我会假设使用

@Cascade({CascadeType.ALL})

然后Hibernate会通过简单地执行以下操作来神奇地从所有关联中删除Employee:

session.delete(employee);

相反,我得到:

Error during managed flush [deleted object would be re-saved by cascade (remove deleted object from associations)

所以,为了尝试让我的代码更清洁,甚至可能优化(有时懒惰的提取就足够了,有时候我需要急切),我试着懒得取几乎所有东西,并希望如果我这样做,例如:< / p>

employee.getFeedbacks()

然后很好地获取反馈,没有任何问题但是没有,一切都破裂了:

failed to lazily initialize a collection of role: ..., could not initialize proxy - no Session

我想到的下一件事就是删除对象插入/删除相关子对象的可能性,但这可能是一个糟糕的想法,在性能方面 - 单独插入每个对象

child.parent=parent

而不是批量

parent.children().add(children)

最后,我看到有多人建议创建我自己的自定义查询和东西,但在那时,为什么我甚至要打扰Hibernate?是不是真的没有办法解决我的问题比较干净,或者我错过了什么,还是我是白痴?

1 个答案:

答案 0 :(得分:0)

如果我正确地理解了这个问题,那就是关于简单1:N关系的层叠。在这种情况下,Hibernate可以很好地完成这项工作:

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, 
        mappedBy = "post", orphanRemoval = true)
    private List<Comment> comments = new ArrayList<>();
}

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne
    private Post post;
}

代码:

Post post = newPost();
doInTransaction(session -> {
    session.delete(post);
});

生成:

delete from Comment where id = 1
delete from Comment where id = 2
delete from Post where id = 1

但是如果你有其他(合成)集合,Hibernate没有机会知道哪些,所以你必须自己处理它们。

对于Hibernate和自定义查询,Hibernate提供的HQL比传统SQL更紧凑,但仍然不如注释透明。