Java “如何调试”;找到了同一集合的两个表示形式;?

Java “如何调试”;找到了同一集合的两个表示形式;?,java,hibernate,jpa,orm,playframework,Java,Hibernate,Jpa,Orm,Playframework,我发现了这一点,但没有一个完整地解释了这个问题,以及如何调试它-答案都是轶事 问题在于,在Play 1.2.4 JPA测试中,当我save()a模型时,会出现此异常: org.hibernate.HibernateException:找到了相同的两个表示形式 集合:models.Position.projects 我想知道: 是否有与游戏无关的一般问题文档?问题出在hibernate上,但谷歌在这方面的很多结果都在Play应用程序中 有哪些基本的最佳实践可以避免这个问题 它是由玩耍引起的吗?还是

我发现了这一点,但没有一个完整地解释了这个问题,以及如何调试它-答案都是轶事

问题在于,在Play 1.2.4 JPA测试中,当我
save()
a模型时,会出现此异常:

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

我想知道:

  • 是否有与游戏无关的一般问题文档?问题出在hibernate上,但谷歌在这方面的很多结果都在Play应用程序中
  • 有哪些基本的最佳实践可以避免这个问题
  • 它是由玩耍引起的吗?还是我做错了什么
  • 如何解决我的具体情况
  • 。我有四个实体:

    @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;
    }
    
    @实体
    公共类人扩展模型{
    公共字符串名称;
    @OneToMany(级联=级联类型.ALL)
    公开名单职位;
    }
    @实体
    公共类位置扩展模型{
    公共位置(){}
    公众职位(公司){
    这是指公司;
    this.projects=new ArrayList();
    }
    @奥内托内
    上市公司;
    @许多酮
    公众人物;
    @独身癖
    公开项目清单;
    }
    @实体
    上市公司扩展模型{
    公共字符串名称;
    }
    @实体
    公共类项目扩展模型{
    公共项目(){}
    公共项目(字符串字段、字符串状态){
    this.theField=字段;
    这个状态=状态;
    }
    @许多酮
    公共职位;
    公共领域;
    公共字符串状态;
    }
    
    和我的持久性代码:

    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();
    
    Company facebook=新公司();
    facebook.name=“facebook”;
    facebook.save();
    公司推特=新公司();
    twitter.name=“twitter”;
    twitter.save();
    人乔=新人();
    joe.name=“joe”;
    joe.save();
    joe.positions=newarraylist();
    职位joeAtFacebook=新职位(facebook);
    添加(新项目(“流”、“架构师”);
    添加(新项目(“消息”,“领导QA”);
    joe.positions.add(joeAtFacebook);
    职位joeAtTwitter=新职位(twitter);
    添加(新项目(“从Facebook偷东西”、“CEO”);
    joe.positions.add(joeatwitter);
    joe.save();
    
    顺便说一句,我试着按照一个人的建议添加,但似乎没有帮助

    我发现创建的表确实在某种意义上是重复的:

    我有一个
    person\u position
    表和一个
    position表,其中都包含类似的字段:
    person\u position
    包含
    person\u id
    positions\u id
    ,而
    position
    表包含
    id
    (意思是位置id),
    person\u id
    ,和
    公司id
    。所以我知道我的模型定义产生了某种非预期的冗余,但我真的不知道如何解决它

    我认为这可能与双向映射有关,但这里有一个问题(我删除了一些反向引用),问题仍然存在。

    试试看

            @OneToMany(mappedBy="position")
            public List<Project> projects;
    
    @OneToMany(mappedBy=“position”)
    公开项目清单;
    
    据我所知,错误是由以下任意组合引起的:

    • @OneToMany
      注释上缺少/缺少
      mappedBy
      参数。此参数应接收目标模型中引用此模型的字段的名称
    • 旧的hibernate-播放1.2.4附带hibernate 3.6.1。。。升级到3.6.8似乎解决了另一个此类问题(只需将以下内容添加到dependencies.yml和play deps)
    -org.hibernate->hibernate核心3.6.8.最终版本:

    force:true

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

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

    我用来调试的步骤:

    • 写了一个测试,重现了这个问题
    • 补充道-我不确定它是否解决了问题的一部分,还是使问题变得更糟
    • 通过hibernate代码进行调试,并意识到这可能表明存在hibernate问题,而不是用户/配置错误
    • 注意到hibernate在3.6.1之后有很多错误修复版本,决定试试运气并升级
    • 同样重要的是,清理tmp文件夹不会对编译的JAR造成伤害,在进行重大更改(如升级hibernate版本)后,可能值得清理它

      • 首先,我想你错过了最后一行之前的第一行:

        joe.positions.add(joeAtTwitter);
        
        第二: 我认为你不应该这样做

        joe.positions = new ArrayList<Position>();
        
        它将解决您的问题,而且它是一种最佳实践,通常使用空集合而不是
        null
        value(请参见有效Java),特别是用于处理Hibernate托管对象。阅读第一段,了解为什么最好使用空集合初始化


        现在我想发生的是:当您调用
        joe.save()
        使对象由Hibernate管理,然后使用新集合覆盖属性时,我不理解为什么您得到的错误是关于
        model.Position.projects
        ,但我想情况就是这样。

        我的猜测-级联问题。添加一个职位,该职位会添加两个项目,然后joe.save()可能会导致添加两次该职位。使用级联选项并报告:)@KenEgozi-级联选项是否影响我的表的生成?因为我有一个重复的表结构本身。。。(我把细节放在问题中)@KenEgozi-通过升级hibernate版本解决-见我的答案。谢谢,谢谢你的帮助。也许我在上面的回答中没有说清楚,但是指定mappedBy属性并从hibernate 3.6.1升级到3.6.8解决了这个问题
        @Entity
        public class Person extends Model {
            public String name;
        
            @OneToMany(cascade = CascadeType.ALL)
            public List<Position> positions = new ArrayList<Position>();
        }