我在类(实体类)Person和Hobby之间有一个EJB多对多(双向)关系。数据库中有相应的表,称为PERSON和HOBBY,以及用于多对多关系的表PERSON_HOBBY。
正如我将在下面详细介绍的那样,问题在于,每当我试图坚持一个有兴趣爱好的人时,我都会遇到外键约束违规。这是因为entityManager尝试将新行保存到PERSON_HOBBY中,其中包含对ID = 0的person-entity的引用,这在PERSON表中不存在。我稍后会再回过头来看,但首先我将展示实体类的相关部分。
首先,这是实体类Person:
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
@ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
/* Note: I used to have CascadeType.PERSIST in the above line as well, but
it caused "Detached object passed to persist" exceptions whenever I tried to
persist a person with hobbies. So I suppose I was right in deleting
CascadeType.PERSIST...? */
@JoinTable(name = "PERSON_HOBBY",
joinColumns = @JoinColumn(name="personId", referencedColumnName="id"),
inverseJoinColumns = @JoinColumn(name="hobbyId", referencedColumnName="id"))
private List<Hobby> hobbies = new ArrayList<Hobby>();
public List<Hobby> getHobbies () {
return hobbies;
}
public void setHobbies (List<Hobby> hobbies) {
this.hobbies = hobbies;
for(Hobby h:hobbies) { // this is to maintain bi-directionality
h.addPerson(this);
}
}
// other getters and setters omitted here.
然后是实体类Hobby:
@Entity
public class Hobby {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false)
private String description;
@ManyToMany(mappedBy = "hobbies", fetch = FetchType.EAGER)
private List<Person> persons;
public Hobby() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// getter and setter for Description omitted here.
public List<Person> getPersons () {
return persons;
}
public void setPersons (List<Person> persons) {
this.persons = persons;
}
public void addPerson (Person p) {
this.persons.add(p);
}
}
我还有一个无状态会话bean,这里显示的与问题相关:
@Stateless
@Default
public class PersonRepositoryImpl implements PersonRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
public Person create(Person p) {
entityManager.persist(p);
entityManager.flush();
return p;
}
@Override
public Person createPersonWithHobbies(Person p, List<Hobby>hobbyLijst) {
p = create(p); // I've also tried simply: create(p);
System.out.println("The newly assigned ID for the persisted
person is: " + p.getId());
// That last line **always** prints the person-ID as being 0 !!!!
p.setHobbies(hobbyLijst);
entityManager.merge(p); // This should save/persist the person's hobby's!
entityManager.flush();
return p;
}
}
现在从我的servlet开始,我一直在尝试两种不同的方式。首先,我尝试在上面的会话bean上调用方法create(p)
。也就是说,在创建一个新的Person实例p之后,设置它的所有非关系字段,并在其上调用setHobbies(从数据库中取出一个非零的Hobby对象列表),我调用了:
personRepo.create(p);
但是这导致了外键(FK)异常:
表'PERSON_HOBBY'上的INSERT导致违反外键 键'(FK_EQAEPVYK583YDWLXC63YB3CXK'为键(0)。该声明 已被退回。“
这里提到的FK约束是PERSON_HOBBY中引用PERSON的约束。
我尝试的第二种方法是从servlet进行以下调用:
personRepo.createPersonWithHobbies(p, hobbyLijst);
其中,就像以前一样,p是新的人物对象;和hobbyLijst是那个人的爱好列表。这导致了与之前调用personRepo.create(p)完全相同的FK异常。
重要的是,方法println
中的createPersonWithHobbies
语句,在新持久化的person-object上调用getId()
,总是将该对象的ID设为0.我认为这解释了FK -exception,因为PERSON表中没有人实体/行,ID为0,也不应该有。但是当然getId()
调用不应该输出0.相反,它应该输出新生成的新持久化人员实体的ID。 (是的,它在PERSON表中正确保存,正确生成的ID> 0。所以PERSON表中有正确的ID - 它似乎对于entityManager和/或容器是不可见的。)< / p>
感谢。