JPA OneToMany/ManyToOne 关系无效 - 我错过了什么?
JPA OneToMany/ManyToOne relationship not working - What am I missing?
我知道这个问题之前已经被问过很多次了,我之所以知道是因为我已经搜索了与我的问题相关的每个问题以尝试找到解决方案,但是 none 提出的解决方案正在为我工作,我很确定我必须遗漏一些东西。
人 Class:
@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;
}
项目 Class:
@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' 和更多的东西,但似乎没有任何效果。
我读到我必须 'join' 在持久化之前手动处理实体,这就是我所做的:
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 上缺少 属性:
<property name="hibernate.id.new_generator_mappings" value="false" />
您还需要一种在对象中添加关系的方法:
public void addToProjects(ProjectEntity project){
project.setPersonid(this);
this.projects.add(project);
}
要完成这项工作,您需要在声明变量时初始化列表:
private List<ProjectEntity> projects = new ArrayList<ProjectEntity>();
就是这样!
这是最终的工作代码,以防任何人发现它有用:):
人 Class:
@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);
}
}
项目 Class:
@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();
希望对您有所帮助!非常感谢。
我能想到的几个线索,因为我遇到过不止一次这样的问题:
除非您想要来自 Project
的级联操作来更新您的 Person
,否则您应该删除
@ManyToOne(级联= CascadeType.ALL)
来自您的 personid
属性
尝试更新您的 projects
集合而不是创建一个新集合,因为如果它已经由 Hibernate 管理(不需要,persist/merge 操作将在旧的上执行一个和一个新的。
人 Class:
private List<ProjectEntity> projects = new ArrayList<>();
您的代码:
personTest.getProjects().addAll(projects);
我通常更喜欢merge
而不是persist
,因为我发现它更多'natural',而且有时,输出明显不一样。
您要注意的主要事情是正确定义关系的拥有方。据我所知,我从(有时难以理解的)官方文档中得出的结论是,拥有方几乎是默认触发级联和透明删除的一方。
比如上面你定义了owning side为ProjectEntity
,那么要让cascaded persistence起作用最重要的一步就是将project添加到PersonEntity.projects
.
然后您将要在关系的拥有方调用 persist
,即
em.persist(projectTest);
如果这没有帮助,我建议您启用 SQL 登录您的 JPA 提供程序以找出它试图执行的语句,尤其是这些实体的执行顺序 insert
ed.
另外,根据现有评论,尝试坚持以人为本。
如果这样做,我认为正确的方法是将 persisted 实体添加到关系中,即:
PersonEntity persistedPerson = em.persist(personTest);
projectTest.setPersonId(persistedPerson);
em.persist(projectTest);
我遇到了同样的问题。一个 @ManyToOne
无缘无故不工作,还有 2 个 类。我添加了 @GeneratedValue(strategy=GenerationType.AUTO)
,但它没有解决我的问题。
我还尝试重命名 类、清理、关闭项目、重新启动等,但 none 有效。最后,我删除了文件(之前制作了一个副本)并从新文件中重新创建了它们,这解决了我的问题。我使用的是 Eclipse 4.8、Spring 2.5、Groovy 2.5、Java 1.8
更新:
不确定是什么问题,无论如何(对于 groovy)检查你的保存方法:myUserRepo(new MyUser("username")),同时检查你的 xxxxRepo < MyUser, Integer> 并检查您的文件是否为 .groovy(最后一个应该没有问题)
其他更新:
如果您在 2 个表之间创建关系并使用保存结果,请务必在服务上使用 @Transactional
并在关系字段中使用 link,例如:
@Transactional
UserAccount save(UserAccount userAccount) {
User user = userRepo.save(new User(userAccount))
UserAccount.setUser(user)
userAccountRepo.save(userAccount)
}
我知道这个问题之前已经被问过很多次了,我之所以知道是因为我已经搜索了与我的问题相关的每个问题以尝试找到解决方案,但是 none 提出的解决方案正在为我工作,我很确定我必须遗漏一些东西。
人 Class:
@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;
}
项目 Class:
@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' 和更多的东西,但似乎没有任何效果。
我读到我必须 'join' 在持久化之前手动处理实体,这就是我所做的:
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 上缺少 属性:
<property name="hibernate.id.new_generator_mappings" value="false" />
您还需要一种在对象中添加关系的方法:
public void addToProjects(ProjectEntity project){
project.setPersonid(this);
this.projects.add(project);
}
要完成这项工作,您需要在声明变量时初始化列表:
private List<ProjectEntity> projects = new ArrayList<ProjectEntity>();
就是这样!
这是最终的工作代码,以防任何人发现它有用:):
人 Class:
@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);
}
}
项目 Class:
@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();
希望对您有所帮助!非常感谢。
我能想到的几个线索,因为我遇到过不止一次这样的问题:
除非您想要来自 Project
的级联操作来更新您的 Person
,否则您应该删除
@ManyToOne(级联= CascadeType.ALL)
来自您的 personid
属性
尝试更新您的 projects
集合而不是创建一个新集合,因为如果它已经由 Hibernate 管理(不需要,persist/merge 操作将在旧的上执行一个和一个新的。
人 Class:
private List<ProjectEntity> projects = new ArrayList<>();
您的代码:
personTest.getProjects().addAll(projects);
我通常更喜欢merge
而不是persist
,因为我发现它更多'natural',而且有时,输出明显不一样。
您要注意的主要事情是正确定义关系的拥有方。据我所知,我从(有时难以理解的)官方文档中得出的结论是,拥有方几乎是默认触发级联和透明删除的一方。
比如上面你定义了owning side为ProjectEntity
,那么要让cascaded persistence起作用最重要的一步就是将project添加到PersonEntity.projects
.
然后您将要在关系的拥有方调用 persist
,即
em.persist(projectTest);
如果这没有帮助,我建议您启用 SQL 登录您的 JPA 提供程序以找出它试图执行的语句,尤其是这些实体的执行顺序 insert
ed.
另外,根据现有评论,尝试坚持以人为本。 如果这样做,我认为正确的方法是将 persisted 实体添加到关系中,即:
PersonEntity persistedPerson = em.persist(personTest);
projectTest.setPersonId(persistedPerson);
em.persist(projectTest);
我遇到了同样的问题。一个 @ManyToOne
无缘无故不工作,还有 2 个 类。我添加了 @GeneratedValue(strategy=GenerationType.AUTO)
,但它没有解决我的问题。
我还尝试重命名 类、清理、关闭项目、重新启动等,但 none 有效。最后,我删除了文件(之前制作了一个副本)并从新文件中重新创建了它们,这解决了我的问题。我使用的是 Eclipse 4.8、Spring 2.5、Groovy 2.5、Java 1.8
更新: 不确定是什么问题,无论如何(对于 groovy)检查你的保存方法:myUserRepo(new MyUser("username")),同时检查你的 xxxxRepo < MyUser, Integer> 并检查您的文件是否为 .groovy(最后一个应该没有问题)
其他更新:
如果您在 2 个表之间创建关系并使用保存结果,请务必在服务上使用 @Transactional
并在关系字段中使用 link,例如:
@Transactional
UserAccount save(UserAccount userAccount) {
User user = userRepo.save(new User(userAccount))
UserAccount.setUser(user)
userAccountRepo.save(userAccount)
}