2015-10-20 82 views
4

我有一个简单的@OneToMany关系的两个对象看起来如下:春季启动JPA - 一对多关系导致无限循环

父:

@Entity 
public class ParentAccount { 

    @Id 
    @GeneratedValue 
    private long id; 
    private String name; 

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "parentAccount") 
    private Set<LinkedAccount> linkedAccounts; 

} 

孩子:

@Entity 
public class LinkedAccount { 

    @Id 
    @GeneratedValue 
    private long id; 

    @ManyToOne(optional = false) 
    private ParentAccount parentAccount; 

    private String name; 

    // empty constructor for JPA 
    public LinkedAccount() { 
    } 

} 

我ma使用Spring CrudRepository来操作这些实体。但是,调用ParentAccount parent = parentAccountRepository.findOne(id);时,某种无限循环的开始发生,冬眠垃圾邮件这遍控制台:

Hibernate: select linkedacco0_.parent_account_id as parent_a6_1_0_, linkedacco0_.id as id1_0_0_, linkedacco0_.id as id1_0_1_, linkedacco0_.aws_id as aws_id2_0_1_, linkedacco0_.key_id as key_id3_0_1_, linkedacco0_.name as name4_0_1_, linkedacco0_.parent_account_id as parent_a6_0_1_, linkedacco0_.secret_key as secret_k5_0_1_ from linked_account linkedacco0_ where linkedacco0_.parent_account_id=? 

我试着改变了获取类型LAZY但后来我得到这个错误:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.berrycloud.scheduler.model.ParentAccount.linkedAccounts, could not initialize proxy - no Session 

(似乎它试图在事务上下文之外执行延迟加载)。

这是我的CRUD库:

@Repository 
public interface ParentAccountRepository extends CrudRepository<ParentAccount, Long> { 
} 

有人能告诉我如何解决这个问题?我更喜欢EAGER获取的解决方案。感谢您的任何提示

编辑:这是我使用

CREATE TABLE parent_account (
    id BIGINT auto_increment, 
    name VARCHAR(80) null, 
    PRIMARY KEY (`id`) 
); 

CREATE TABLE linked_account (
    id BIGINT auto_increment, 
    parent_account_id BIGINT, 
    name VARCHAR(80) null, 
    FOREIGN KEY (`parent_account_id`) REFERENCES `parent_account` (`id`), 
    PRIMARY KEY (`id`) 
); 
+0

那么,每个父帐户有几个链接的帐户。而已。我没有看到这可以解析成树图。深度应该是1. – Smajl

+0

在您的映射或模式中没有错误...我不认为您的无限循环问题来自...您是否在做这些对象中的其他任何事情?一些JSON/Jackson注释可能? – Pras

回答

5

问题解决了。我正在引用ParentAccount的LinkedAccount中使用自定义的@toString方法。我不知道这可能会导致任何问题,因此我没有在我的问题中包含toString。

显然,这导致了无限循环的延迟加载,并删除此引用解决了问题。

0

像这样的东西不起作用的架构?

@Entity 
public class Account { 

    @Id 
    @GeneratedValue 
    private long id; 
    private String name; 

    @ManyToOne(cascade={CascadeType.ALL}) 
    @JoinColumn(name="manager_id") 
    private Account manager; 

    @OneToMany((fetch = FetchType.EAGER, mappedBy="manager") 
    private Set<Account> linkedAccounts = new HashSet<Account>(); 

} 
+0

我将不得不编辑我的sql模式(已存在)来添加manager_id列。此外,春天有这样做的自动,所以我想用默认的JPA的JPA方式来解决这个问题 – Smajl

+0

什么是非弹簧JPA呢?顺便说一句,你的代码适合我,你的数据库中的数据有错误。检查两次。 – Mejmo

+0

我编辑了我的问题并添加了我正在使用的模式。也许有什么问题呢? – Smajl

6

作为第一答案提示:

Do not use Lombok's @Data annotation on @Entity classes.

原因是:@Data生成hashcode()equals()toString()方法,其使用所生成的吸气剂。使用吸气手段当然可以获取新数据,即使属性标记为FetchType = LAZY

某处hibernate试图用toString()记录数据并崩溃。

+0

龙目确实是内存模型创建无限循环的原因,在我的情况下最终导致了StackOverflowError。尽管如此,我发现龙目岛的getters和setters一代太有用了,完全放弃了它。 因此,我只通过将我自己的_toString()_方法添加到刚刚返回_super.toString()_的类来禁用Lombok生成_toString()_并解决了我的问题。 – Lev