首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hibernate良好实践,懒惰/急切地加载和保存/删除子项(帮助我Hibernate sensei)

Hibernate良好实践,懒惰/急切地加载和保存/删除子项(帮助我Hibernate sensei)
EN

Stack Overflow用户
提问于 2016-10-05 18:55:01
回答 1查看 1.1K关注 0票数 1

因此,我发现自己在Hibernate方面陷入了相当的困境。当我开始开发我的web应用程序时,我在任何地方都使用“渴望”加载,这样我就可以轻松地访问孩子、父母等。

过了一段时间,我遇到了我的第一个问题--重新保存已删除的对象。多个堆栈溢出线程建议我应该从它所在的所有集合中删除该对象。阅读这些建议让我感到“蜘蛛式的感觉”,因为我的关系并不是真的很简单,我不得不迭代多个对象,这让我的代码看起来有点丑陋,让我怀疑这是不是最好的方法。

例如,删除员工时(从某种意义上说,该员工属于用户,用户可以充当多个不同的员工)。假设员工可以将反馈留给Party,这样员工可以有多个反馈,Party也可以有多个反馈。此外,Employee和Party都属于某种父对象,比如说Organization。基本上,我们有:

代码语言:javascript
复制
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;
}

以下是我在删除员工时得到的结果:

代码语言:javascript
复制
// 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);

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

代码语言:javascript
复制
@Cascade({CascadeType.ALL})

然后Hibernate会神奇地将Employee从所有关联中删除,只需执行以下操作:

代码语言:javascript
复制
session.delete(employee);

相反,我得到的是:

代码语言:javascript
复制
Error during managed flush [deleted object would be re-saved by cascade (remove deleted object from associations)

因此,为了让我的代码更整洁,甚至是优化(有时延迟抓取就足够了,有时我需要渴望),我尝试了延迟抓取几乎所有的东西,并希望如果我这样做了,例如:

代码语言:javascript
复制
employee.getFeedbacks()

然后,反馈被很好地获取,没有任何问题,但不是,一切都会崩溃:

代码语言:javascript
复制
failed to lazily initialize a collection of role: ..., could not initialize proxy - no Session

我考虑的下一件事是消除对象插入/删除其相关子对象的可能性,但从性能上讲这可能不是一个好主意-使用

child.parent=parent

而不是批量使用

parent.children().add(children)

最后,我看到许多人推荐创建我自己的自定义查询和东西,但在这一点上,我为什么还要费心使用Hibernate呢?是不是真的没有好的方法来处理我的问题呢?还是我错过了什么,或者我是个笨蛋?

EN

回答 1

Stack Overflow用户

发布于 2016-10-05 19:21:35

如果我没理解错的话,这一切都是关于通过简单的1:N关系进行级联的。在这种情况下,Hibernate可以很好地完成这项工作:

代码语言:javascript
复制
@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;
}

代码:

代码语言:javascript
复制
Post post = newPost();
doInTransaction(session -> {
    session.delete(post);
});

生成:

代码语言:javascript
复制
delete from Comment where id = 1
delete from Comment where id = 2
delete from Post where id = 1

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39872070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档