Это заставило меня остаться в тупике на несколько часов.Это связано с моим другим вопросом здесь:
JPA / hibernate - Невозможно добавить или обновить дочернюю строку: ограничение внешнего ключа не выполняется - НО запись существует
Я избавилсяпочти весь код и сузили проблему.У меня есть три очень простых объекта:
@Entity
public class Building {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
public Building() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Other.java
@Entity
public class Other {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
@JoinColumn(name = "building_id")
private Building building;
public Other() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Building getBuilding() {
return building;
}
public void setBuilding(Building school) {
this.building = school;
}
}
Event.java
@Entity
public class Event {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@ManyToOne
@JoinColumn(name = "other_id")
private Other other;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Other getOther() {
return other;
}
public void setOther(Other other) {
this.other = other;
}
}
Это не удастся с нарушением ограничения внешнего ключа:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`blah`.`event`, CONSTRAINT `FK403827A76D0546B` FOREIGN KEY (`other_id`) REFERENCES `Other` (`id`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
СЕЙЧАС ЗДЕСЬ ДЕЙСТВИТЕЛЬНО ЧУВСТВЕННАЯ ЧАСТЬ !!!!Если я сделаю рефактор затмения и переименую «Другой» объект в «Боб», он будет работать отлично.Точно так же мы находимся на той же странице, сущность Event теперь будет выглядеть так:
@Entity
public class Event {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@ManyToOne
@JoinColumn(name = "bob_id")
private Bob bob;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Bob getBob() {
return bob;
}
public void setBob(Bob bob) {
this.bob = bob;
}
}
И теперь она работает отлично.Может кто-нибудь объяснить это новичку Hibernate, как я?Это действительно поставило меня в тупик.Сбой, когда я сохраняю новое событие в базе данных на моем уровне обслуживания:
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public void addEvent(Event event) throws ErrorCodeException, Exception
{
// not sure if I need to do this, still fails if I remove it
event.setOther(otherDAO.getReferenceById(event.getOther().getId()));
eventDAO.persist(event);
}
Еще один комментарий.Вместо того, чтобы переименовать Другое в Боба, я также могу установить имя таблицы в нижний регистр:
@Entity
@Table(name = "other")
public class Other {
Это также исправляет это.Но я не могу принять эти решения.Я хочу знать, почему это не удается.Я принял технологическое решение не использовать Grails, чтобы избежать этого типа «магии».
Вот журналы спящего режима SQL:
// Initial database inserts
Hibernate: insert into Building values ( )
Hibernate: insert into Other (building_id) values (?)
// Insert which throws exception
Hibernate: insert into Event (other_id) values (?)
2011-06-27 11:31:51 JDBCExceptionReporter [WARN] SQL Error: 1452, SQLState: 23000
2011-06-27 11:31:51 JDBCExceptionReporter [ERROR] Cannot add or update a child row: a foreign key constraint fails (`blah`.`event`, CONSTRAINT `FK403827A76D0546B` FOREIGN KEY (`other_id`) REFERENCES `Other` (`id`))
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.blah.server.domain.Event]; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.blah.server.domain.Event]