JPA - Перенос однонаправленного отношения "один к большому" терпит неудачу с EclipseLink
Я пытаюсь сохранить очень простое отношение однонаправленного от одного до большого, но EclipseLink (2.3.1) терпит неудачу.
Класс обслуживания (родительский):
@Entity
@Table(name = "tbl_service2")
public class Service implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="service_id")
public long serviceID;
@Column(name="name")
public String name;
@OneToMany(cascade={CascadeType.ALL})
@JoinColumn(name="service_id", referencedColumnName="service_id")
public Set<Parameter> parameters;
}
Класс параметров (ребенок):
(Конечно, в базе данных есть поле "service_id" внешнего ключа, которое не представлено в классе, поскольку это однонаправленное отношение).
@Entity
@Table(name = "tbl_service_parameters2")
public class Parameter implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="param_id")
public long parameterID;
@Column(name="name")
public String name;
}
И это код для сохранения сущностей:
Service service = new Service();
service.parameters = new HashSet<Parameter>();
service.name = "test";
Parameter param = new Parameter();
param.name = "test";
service.parameters.add(param);
em.persist(service);
em.flush();
Я получаю это исключение:
Internal Exception: java.sql.SQLException: Field 'service_id' doesn't have a default value
Error Code: 1364
Call: INSERT INTO tbl_service_parameters2 (name) VALUES (?)
bind => [test]
РЕДАКТИРОВАТЬ: Поле базы данных service_id
имеет (и должно иметь) непустое ограничение из-за характера данных.
Является ли это ошибкой или что-то не так в коде?
Ответы
Ответ 1
Попробуйте удалить ненулевое ограничение в поле service_id таблицы параметров. Eclipselink будет обновлять внешний ключ для однонаправленных столбцов соединения 1: m в отдельном заявлении, поэтому вам нужно отключить или задержать проверку ограничения. Использование двунаправленного поля позволит обновить поле fp с остальными данными параметров.
Ответ 2
Используйте nullable = false
, на @JoinColumn
:
@JoinColumn(name = "service_id", nullable = false)
Ответ 3
Вы можете изменить свою персистентность для версии hibernate < 4.0, и ваш код будет работать хорошо. "Ну" в ссылке "для отношения" один ко многим "сохранить/перенести родительский ТОЛЬКО, НЕ сохранять/сохранять дочернюю коллекцию по отдельной задаче"
Ответ 4
Мне удалось заставить его работать в Oracle, используя отложенный внешний ключ.
Пример:
ALTER TABLE my_table ADD CONSTRAINT my_constraint_name FOREIGN KEY (my_table_column) REFERENCES foreign_key_table (foreign_key_table_column) DEFERRABLE INITIALLY DEFERRED
Ответ 5
Как я узнал, в таких случаях внешний ключ заполняется отдельным выражением. В моем примере я использовал Address
entity с customer_id
как внешний ключ.
2014-07-08T20:51:12.752+0300|FINE: INSERT INTO ADDRESS (address_id, street, city, region) VALUES (?, ?, ?, ?)
bind => [10, foo, foo, foo]
2014-07-08T20:51:12.753+0300|FINEST: Execute query InsertObjectQuery([email protected])
2014-07-08T20:51:12.757+0300|FINEST: Execute query DataModifyQuery(sql="UPDATE ADDRESS SET customer_id = ? WHERE (address_id = ?)")
2014-07-08T20:51:12.757+0300|FINE: UPDATE ADDRESS SET customer_id = ? WHERE (address_id = ?)
bind => [151, 10]
Следовательно, наличие @JoinColumn
с nullable=true
вызывает ошибку.
В качестве альтернативы вы можете использовать @OneToMany (..., orphanRemoval = true, ...)
.
Ответ 6
По умолчанию nullable имеет значение true в @JoinColumn, в то время как данные сохраняются в отношении один-ко-многим, мы должны сделать nullable как false, чтобы избежать исключений нарушения данных, возникающих во время выполнения.