2011-12-14 65 views
14

我找到了severalquestionsabout这个,但没有一个完整地解释了问题,以及如何调试它 - 答案都是轶事。如何调试“找到两个相同集合的表示”?

的问题是,在播放1.2.4 JPA测试,我得到这个异常,当我save()模型:

org.hibernate.HibernateException:找到相同 收集的两种表示:车型.Position.projects

我想知道:

  1. 有总的来说,联合国这一问题的文件与Play相关?问题在于休眠,但Google的很多结果都在Play应用中。
  2. 避免此问题的一些基本最佳实践是什么?
  3. 它是由Play引起的吗?或者我做错了什么?
  4. 如何解决在我的具体情况?

Here is a reproduction of the problem on github。我有四个实体:

@Entity 
public class Person extends Model { 
    public String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    public List<Position> positions; 
} 


@Entity 
public class Position extends Model { 
    public Position(){} 
    public Position(Company companies) { 
     this.companies = companies; 
     this.projects = new ArrayList<Project>(); 
    } 

    @OneToOne 
    public Company companies; 

    @ManyToOne 
    public Person person; 

    @OneToMany 
    public List<Project> projects; 
} 

@Entity 
public class Company extends Model { 
    public String name; 
} 

@Entity 
public class Project extends Model { 
    public Project(){} 
    public Project(String field, String status){ 
     this.theField = field; 
     this.status = status; 
    } 

    @ManyToOne 
    public Position position; 

    public String theField; 
    public String status; 
} 

而且我的坚持代码:

Company facebook = new Company(); 
facebook.name = "Facebook"; 
facebook.save(); 
Company twitter = new Company(); 
twitter.name = "Twitter"; 
twitter.save(); 

Person joe = new Person(); 
joe.name = "Joe"; 
joe.save(); 

joe.positions = new ArrayList<Position>(); 

Position joeAtFacebook = new Position(facebook); 
joeAtFacebook.projects.add(new Project("Stream", "Architect")); 
joeAtFacebook.projects.add(new Project("Messages", "Lead QA")); 
joe.positions.add(joeAtFacebook); 

Position joeAtTwitter = new Position(twitter); 
joeAtTwitter.projects.add(new Project("Steal stuff from Facebook", "CEO")); 
joe.positions.add(joeAtTwitter); 
joe.save(); 

顺便说一句,我试着加入Play associations module作为一个人建议,以及简化版,它似乎帮助。

我看到的确是创建的表是重复的感觉:

我同时拥有person_position表和position table,其中都含有类似领域:person_position包含Person_idpositions_id,而position表包含id(意思是位置id),person_idcompanies_id。所以我明白某种意想不到的冗余是由我的模型定义创建的,但我并不真正了解如何解决它。

我认为这可能与双向映射有关,但这里是一个branch where the model is uni-directional(我删除了一些反向引用) - 问题仍然存在。

+0

我的猜测 - 级联问题。你添加一个位置,并且该位置添加两个项目,那么joe.save()可能会导致两次添加位置。玩Cascade选项并回报:) – 2011-12-14 23:41:15

+0

@KenEgozi - 做级联选项会如何生成我的表格?因为我在表结构本身中有一个重复...(我把细节放在问题中) – ripper234 2011-12-15 05:47:04

+0

@KenEgozi - 通过升级休眠版本解决 - 请参阅我的答案。谢谢。 – ripper234 2011-12-15 14:11:40

回答

7

尝试

 @OneToMany(mappedBy="position") 
        public List<Project> projects; 
+0

这是解决方案的一部分,谢谢。 – ripper234 2011-12-15 14:53:10

9

据我已经能够告诉,错误是由任意组合引起的:

  • 缺少/上@OneToMany注释丢失mappedBy参数。该参数应该接收目标模型中引用该模型的字段的名称。
  • 旧的休眠 - 播放1.2.4与休眠3.6.1船...升级到3.6.8似乎解决另一个这样的问题(只需添加以下依赖项。阳明,发挥DEPS)

- org.hibernate -> hibernate-core 3.6.8.Final:

force: true

对于我来说,上面的步骤解决问题

这实际上是hibernate中的一个bug,因为它在持久化对象时被抛出,而实际上却意味着创建模式时应该检测到的“设计时间”问题。

步骤我用来调试:

  • 写了一个测试,记录并再生的问题
  • 添加了associations module - 我不知道这是否解决了问题的一部分,或使病情加重。
  • 通过hibernate代码进行调试,并意识到这可能表示休眠问题,而不是用户/配置错误。
  • 注意到hibernate在3.6.1之后有很多bugfix版本,并且决定尝试我的运气并升级。
  • 同样重要的是,清理tmp文件夹不会伤害 - 在缓存中编译jar文件,并且在像升级hibernate版本这样的重大更改之后,清理它可能是值得的。
1

首先,我认为你之前的最后一次错过行一个:

joe.positions.add(joeAtTwitter); 

二: 我认为你不应该做

joe.positions = new ArrayList<Position>(); 

,而不是改变Person到:

@Entity 
public class Person extends Model { 
    public String name; 

    @OneToMany(cascade = CascadeType.ALL) 
    public List<Position> positions = new ArrayList<Position>(); 
} 

它会解决您的问题,再加上这是一个最佳实践,使用空集合而不是null值(请参阅Effective Java),特别是使用Hibernate管理对象。请阅读第一段here以解释为什么您最好使用空集合进行初始化。

现在我认为是发生的情况是:当你调用joe.save()你做管理的对象(由Hibernate),那么你重写属性有一个新的集合,我不明白为什么你得到了误差约为model.Position.projects,但我认为是这样。

相关问题