如何调试“找到同一个集合的两个表示”?

时间:2011-12-14 16:32:45

标签: java hibernate jpa orm playframework

我已找到several questions about这个,但没有一个完整地解释问题,以及如何调试它 - 答案都是轶事。

问题是在Play 1.2.4 JPA测试中,当我save()模型时,我收到此异常:

  

org.hibernate.HibernateException:找到两个相同的表示   集合:models.Position.projects

我想知道:

  1. 是否有关于此问题的文档,与Play无关?这个问题处于休眠状态,但很多谷歌的结果都在Play应用程序中。
  2. 有哪些基本的最佳做法可以避免此问题?
  3. 是否由Play引起?或者我做错了什么?
  4. 如何解决我的具体情况?
  5. 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 1}}表包含id(表示位置ID),person_idcompanies_id。所以我理解我的模型定义会创建某种非预期的冗余,但我真的不明白如何解决它。

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

3 个答案:

答案 0 :(得分:9)

据我所知,错误是由以下任意组合引起的:

  • mappedBy注释中缺少/缺少@OneToMany参数。此参数应该接收目标模型中引用该模型的字段的名称。
  • 旧的休眠 - 播放1.2.4附带hibernate 3.6.1 ...升级到3.6.8似乎解决了另一个这样的问题(只需将以下内容添加到dependencies.yml,并播放deps)

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

force: true

对我来说,上述步骤解决了问题

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

我以前调试的步骤:

  • 写了一个重现问题的测试
  • 添加了associations module - 我不确定它是否解决了问题的一部分,或者使问题变得更糟。
  • 通过hibernate代码调试,并意识到这可能表示一个休眠问题,而不是用户/配置错误。
  • 注意到hibernate在3.6.1之后有相当多的bugfix版本,并决定试试运气并升级。
  • 同样重要的是,清理tmp文件夹不会受到影响 - 在那里缓存已编译的jar文件,并且在升级hibernate版本等重大更改之后,清理它可能是值得的。

答案 1 :(得分:7)

尝试

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

答案 2 :(得分: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,但我认为就是这种情况。