Hibernate @Version causing database foreign key constraint failure

拜拜、爱过 提交于 2020-01-16 19:12:08

问题


I have two hibernate/JPA entities

@Entity
@Table(name = "conference_room", uniqueConstraints = @UniqueConstraint(columnNames = "code"))
class ConferenceRoom {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer     id;
    @Column(name = "code", unique = true, length = 20)
    private String      code;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "conferenceRoom")
    @Cascade({CascadeType.ALL})
    private Set<Person> people       = new HashSet<Person>();
    // Appropriate getters and setters
}

@Entity
@Table(name = "person")
class Person {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer     id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "conference_room_code", referencedColumnName = "code")
    private ConferenceRoom  conferenceRoom ;
    // Appropriate getters and setters
}

More over in my database schema I have foreign key contraint on person.conference_room_code that references conference_room.code column.

With in a spring @Transactional method if I do following

public ConferenceRoom getNewConferenceRoom(Person p) {
    ConferenceRoom r = new ConferenceRoom();
    r.setCode("MyUniqueGeneratedCode");
    r.getPeople().add(p);
    // sessionFactory is spring injected member
    sessionFactory.getCurrentSession().merge(r); 
}

Everything is saved correctly, the row for person is updated properly and new conference_room row is added.

But then I tried to add support for optimistic locking db updates to Person class on Date field, so new Person class

@Entity
@Table(name = "person")
class Person {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer         id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "conference_room_code", referencedColumnName = "code")
    private ConferenceRoom  conferenceRoom ;

    @Version
    @Column(name = "updated", length = 19)
    private Date            updated;
    // Appropriate getters and setters
}

This new 'updated' column in MYSQL timestamp column with default value of current_timestamp on insert and updates.

Now if the above method is executed I get

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row: a foreign key constraint fails (`schema`.`person`, CONSTRAINT `fk_room_code` FOREIGN KEY (`conference_room_code`) REFERENCES `conference_room` (`code`) ON DELETE NO ACTION ON UPDATE NO ACTION)
 ....

I tried adding a @Version field to ConferenceRoom, but that didn't work.

I can't understand why adding @Version messes things up. If I remove foreign key constraint or the newly added @Version field, code again starts working, without any exceptions.

I don't want to drop the foreign key constraint. Is there any other way around this problem.


回答1:


First:

More over in my database schema I have foreign key contraint on person.conference_room_code that references conference_room.code column.

Your FK should reference the PK of the referenced entity. In the instant case, you should have person.conference_room_id which references conferenceroom.id. If you want your code to be the identifying field for the ConferenceRoom entity, then don't use a surrogate key. If the code column isn't a PK candidate, then it is also not an FK candidate.

Second:

Merge:

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge"

Persist:

Make a transient instance persistent. This operation cascades to associated instances if the association is mapped with cascade="persist"


I think you have confused merge with persist. From what I can tell by the provided code, you are creating a new ConferenceRoom and not modifying an existing one. Therefore, merge is not going to do what you want it to do. Try changing your (provided) method to the following:

public ConferenceRoom getNewConferenceRoom(Person p) {
    ConferenceRoom r = new ConferenceRoom();
    r.setCode("MyUniqueGeneratedCode");
    r.getPeople().add(p);
    // sessionFactory is spring injected member
    sessionFactory.getCurrentSession().persist(r); 
}

These things should fix the issues you have raised.



来源:https://stackoverflow.com/questions/16152539/hibernate-version-causing-database-foreign-key-constraint-failure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!