0

我有两个休眠/JPA 实体

@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
}

此外,在我的数据库模式中,我在 person.conference_room_code 上有外键约束,它引用了 conference_room.code 列。

@Transactional如果我按照弹簧方法使用

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); 
}

一切都已正确保存,人员行已正确更新并添加了新的会议室行。

但后来我尝试在 Date 字段上添加对乐观锁定数据库更新的支持 Person 类,所以新的 Person 类

@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
}

MYSQL 时间戳列中的这个新的“更新”列,插入和更新时默认值为 current_timestamp。

现在,如果执行上述方法,我会得到

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)
 ....

我尝试在 中添加一个@Version字段ConferenceRoom,但这没有用。

我不明白为什么添加 @Version 会搞砸。如果我删除外键约束或新添加的 @Version 字段,代码将再次开始工作,没有任何异常。

我不想放弃外键约束。有没有其他方法可以解决这个问题。

4

1 回答 1

0

首先

此外,在我的数据库模式中,我在 person.conference_room_code 上有外键约束,它引用了 conference_room.code 列。

您的 FK 应该引用被引用实体的 PK。在本例中,您应该有person.conference_room_id哪些引用conferenceroom.id。如果您希望您code成为ConferenceRoom实体的标识字段,请不要使用代理键。如果该code列不是 PK 候选,那么它也不是 FK 候选。

第二

合并

将给定对象的状态复制到具有相同标识符的持久对象上。如果当前没有与会话关联的持久实例,它将被加载。返回持久实例。如果给定实例未保存,则保存副本并将其作为新的持久实例返回。给定的实例不会与会话关联。如果关联使用 cascade="merge" 映射,则此操作级联到关联实例

坚持

使瞬态实例持久化。如果关联映射为 cascade="persist",则此操作级联到关联实例


我想你已经混淆mergepersist。从我提供的代码可以看出,您正在创建一个新的ConferenceRoom而不是修改现有的。因此,merge不会做你想让它做的事情。尝试将您的(提供的)方法更改为以下内容:

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); 
}

这些东西应该可以解决您提出的问题。

于 2013-04-22T18:42:14.823 回答