EJB / JPA:尝试在多对多关系中持久保存实体时出现外键约束违规

时间:2017-02-16 10:08:54

标签: java hibernate jpa ejb foreign-key-relationship

我在类(实体类)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>

感谢。

0 个答案:

没有答案