【问题标题】:JPA OneToMany/ManyToOne relationship not working - What am I missing?JPA OneToMany/ManyToOne 关系不起作用 - 我错过了什么?
【发布时间】:2018-09-08 07:35:49
【问题描述】:

我知道这已经被问过很多次了,我知道是因为我已经搜索了与我的问题相关的每个问题以尝试找到解决方案,但是,没有一个建议的解决方案对我有用,我'我很确定我一定错过了什么。

人物类:

@Entity
@Table(name = "person", schema = "test")
public class PersonEntity {
    @Id
    @Column(name = "id")
    private long id;
    @Basic
    @Column(name = "name")
    private String name;
    @Basic
    @Column(name = "age")
    private int age;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "personid")
    private List<ProjectEntity> projects;

}

项目类:

@Entity
@Table(name = "project", schema = "test")
public class ProjectEntity {
    @Id
    @Column(name = "id")
    private long id;
    @Basic
    @Column(name = "name")
    private String name;
    @Basic
    @Column(name = "budget")
    private int budget;
    @JoinColumn(name = "personid", referencedColumnName = "id")
    @ManyToOne(cascade = CascadeType.ALL)
    private PersonEntity personid;
}

我有一个双向的 OneToMany/ManyToOne 关系,我尝试过改变 将级联类型添加到 PERSIST,添加 'optional=false' 和更多的东西,但似乎没有任何效果。

我读到我必须在持久化之前手动“加入”实体,这就是我所做的:

    em = JPAUtility.getEntityManager();
    em.getTransaction().begin();

    PersonEntity personTest = new PersonEntity();
    personTest.setName("Test");
    personTest.setAge(23);

    ProjectEntity projectTest = new ProjectEntity();
    projectTest.setName("hello");
    projectTest.setBudget(232);

    projectTest.setPersonid(personTest);

    List<ProjectEntity> projects = new ArrayList<ProjectEntity>();
    projects.add(projectTest);

    personTest.setProjects(projects);

    em.persist(personTest);
    em.getTransaction().commit();
    em.close();

    return personTest;

但我还是明白了:

Caused by: 
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 
Cannot add or update a child row: a foreign key constraint fails 
(`test`.`project`, CONSTRAINT `FK_Personid` FOREIGN KEY (`personid`) REFERENCES
 `person` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

老实说,我不知道自己错过了什么,如果有人有任何建议,我将非常乐意尝试。

非常感谢!


解决方案

感谢所有建议,我设法解决了这个问题,基本上,我错过了我删除的 @GeneratedValue(strategy=GenerationType.AUTO) 注释,因为我认为它不起作用但是它不起作用,因为我错过了一个属性persistence.xml:

&lt;property name="hibernate.id.new_generator_mappings" value="false" /&gt;

I found this info here

您还需要一个方法来在对象中添加关系:

public void addToProjects(ProjectEntity project){ project.setPersonid(this); this.projects.add(project); }

要完成这项工作,您需要在声明变量时初始化 List:

private List&lt;ProjectEntity&gt; projects = new ArrayList&lt;ProjectEntity&gt;();

就是这样!

这是最终的工作代码,以防任何人发现它有用:):

人物类:

@Entity
@Table(name = "person", schema = "test")
public class PersonEntity {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name = "id")
    private long id;
    @Basic
    @Column(name = "name")
    private String name;
    @Basic
    @Column(name = "age")
    private int age;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "personid")
    private List<ProjectEntity> projects = new ArrayList<ProjectEntity>();

    public void addToProjects(ProjectEntity project) {
     project.setPersonid(this);
     this.projects.add(project);
    }
}

项目类:

@Entity
@Table(name = "project", schema = "test")
public class ProjectEntity {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name = "id")
    private long id;
    @Basic
    @Column(name = "name")
    private String name;
    @Basic
    @Column(name = "budget")
    private int budget;
    @JoinColumn(name = "personid", referencedColumnName = "id")
    @ManyToOne(cascade = CascadeType.PERSIST)
    private PersonEntity personid;

    public void setPersonid(PersonEntity personid) {
       this.personid = personid;
    }
}

确保将孩子添加到他们的父母,反之亦然(addToProjects())

    em = JPAUtility.getEntityManager();
    em.getTransaction().begin();

    PersonEntity personTest = new PersonEntity();
    personTest.setName("Butters");
    personTest.setAge(10);

    ProjectEntity projectTest = new ProjectEntity();
    projectTest.setName("Hanks");
    projectTest.setBudget(10000);

    ProjectEntity projectTest2 = new ProjectEntity();
    projectTest2.setName("X");
    projectTest2.setBudget(100);

    personTest.addToProjects(projectTest);
    personTest.addToProjects(projectTest2);

    em.persist(personTest);

    em.getTransaction().commit();
    em.close();

希望对您有所帮助!非常感谢。

【问题讨论】:

  • 先保存 PersonEntity,然后将保存的实体添加到 ProjectEntity,然后保存 ProjectEntity。项目需要 Person 才能持久化。
  • “我已经搜索了与我的问题相关的所有问题以尝试找到解决方案,但是,没有一个建议的解决方案对我有用......” 我认为你这样做是错误的。我建议阅读相关的问答,以深入了解/理解像您这样的问题。然后用这些知识来解决你的问题。
  • @ObiWan-PallavJha 感谢您的建议!不幸的是,它似乎不起作用:/。我在project.setPersonId(personTest) 之前添加了em.persist(personTest);,然后:em.persist(projectTest)。我有错吗?
  • @StephenC 你是 101% 正确的,我没有正确解释自己。这不像我只是在寻找解决方案并试图仅仅为了它而应用它们。我已经阅读了很多问答,试图了解我做错了什么,我已经看过教程,阅读了文档等。不过,我无法让它工作,我有点绝望,这就是我尝试的原因现在什么都可以。非常感谢您的建议。

标签: java mysql hibernate jpa persist


【解决方案1】:

我能想到的几个线索,因为我不止一次越过这种问题:

除非您希望从Project 进行级联操作来更新您的Person,否则您应该删除 @ManyToOne(级联 = CascadeType.ALL) 来自您的personid 属性

尝试更新您的projects 集合,而不是创建一个新集合,因为如果它已经由 Hibernate 管理(不需要,持久/合并操作将在旧集合和新集合上执行。

人物类:

private List<ProjectEntity> projects = new ArrayList<>();

你的代码:

 personTest.getProjects().addAll(projects);

我通常更喜欢merge 而不是persist,因为我觉得它更“自然”,有时,输出显然不一样。

【讨论】:

  • 我只是将级联类型改为 PERSIST,比 ALL 好。我无法将项目添加到“原始”列表中,因为它没有被初始化。 private List&lt;ProjectEntity&gt; projects = new ArrayList&lt;&gt;();这解决了问题,我不知道为什么我没有想到在那里初始化变量。合并给了我相同的结果(在这种情况下)。现在我有了这个:personTest.getProjects().add(projectTest);em.persist(personTest); 这会插入人员和项目,但使用personid = null。进步!非常感谢你帮了我很多忙!
  • 我很困惑:您是说您的personid 对象为空,还是数据库中的关联行为空?当您插入它或在获取查询之后它是否为空?
  • 对不起,我真的不擅长解释事情。当我进行插入时,数据库中的关联行为空:)。不过没关系,我终于成功了!我终于可以坚持父对象及其子对象了!我错过了@GeneratedValue(strategy=GenerationType.AUTO) 注释,因为它不起作用,所以我删除了它,但它不起作用,因为它需要persistence.xml 上的这个属性:&lt;property name="hibernate.id.new_generator_mappings" value="false" /&gt; 非常感谢您的帮助!你真的帮了我!
【解决方案2】:

您需要注意的主要事情是正确定义关系的拥有方。据我记得,我从(有时难以理解)官方文档中得出的结论是,拥有方几乎是默认触发级联和透明删除的一方。

例如,在上面,您已将拥有方定义为ProjectEntity,因此级联持久性工作最重要的一步是将项目添加到PersonEntity.projects

然后您需要在关系的拥有方调用persist,即

em.persist(projectTest);

如果这没有帮助,我建议您在 JPA 提供程序中启用 SQL 日志记录,以找出它正在尝试执行的语句,尤其是这些实体在 inserted 时的顺序。

还可以根据现有的 cmets 尝试先坚持人。 如果你这样做,我相信正确的方法是将 persisted 实体添加到关系中,即:

PersonEntity persistedPerson = em.persist(personTest);
projectTest.setPersonId(persistedPerson);
em.persist(projectTest);

【讨论】:

  • 我在将项目添加到 PersonEntity 后尝试了em.persist(projectTest);,但是,它只插入项目并使用personid = null。但是,如果我这样做:personTest.getProjects().add(projectTest);em.persist(personTest); 他们都被插入到数据库中!不幸的是,该项目仍在personid = null; 中,但我已经接近了哈哈。 em.persist 返回无效。我还认为它会返回持久化的实体,但我错了:)。非常感谢!
  • 我有一个想法 - 您是否尝试过手动分配 ID 字段?否则,添加@Generated 可能会有所帮助。但是,除非数据库本身没有定义 PK,否则我会预料到主键约束失败...
  • 非常感谢您的建议!我尝试手动分配 ID 字段,但它不起作用。然后我尝试再次添加@GeneratedValue(strategy=GenerationType.AUTO),我之前删除了它,因为它不起作用,但是,它不起作用,因为我在persistence.xml:&lt;property name="hibernate.id.new_generator_mappings" value="false" /&gt;上缺少这个属性。我现在可以插入父对象及其子对象,并且它们的 parentid 设置正确:)!非常感谢,如果没有你的帮助,我不知道我是否能弄明白!
【解决方案3】:

我遇到了同样的问题。一个 @ManyToOne 无缘无故无法工作,还有 2 个班级。我添加了@GeneratedValue(strategy=GenerationType.AUTO),但它并没有解决我的问题。

我还尝试重命名类、清理、关闭项目、重新启动等,但都没有奏效。最后,我删除了文件(之前制作了副本)并从新文件重新创建它们,这解决了我的问题。我使用的是 Eclipse 4.8、Spring 2.5、Groovy 2.5、Java 1.8

更新: 不太确定是什么问题,无论如何(对于 groovy)检查您的保存方法:myUserRepo(new MyUser("username")),同时检查您的 xxxxRepoMyUser , Integer> 并检查您的文件是否为 .groovy(最后一个应该不是问题)

其他更新: 如果您要在 2 个表之间创建关系并使用保存结果,请务必在服务上使用 @Transactional 并链接关系字段,例如:

@Transactional
UserAccount save(UserAccount userAccount) {
    User user = userRepo.save(new User(userAccount))
    UserAccount.setUser(user)
    userAccountRepo.save(userAccount)
}

【讨论】:

  • 我也使用了 CrudRepo,反正所有相关的类都被删除并重新创建了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-17
  • 1970-01-01
  • 2016-11-14
  • 1970-01-01
  • 2013-06-17
  • 2013-08-20
  • 1970-01-01
相关资源
最近更新 更多