Подтвердить что ты не робот

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 имеет (и должно иметь) непустое ограничение из-за характера данных.

Является ли это ошибкой или что-то не так в коде?

4b9b3361

Ответ 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, чтобы избежать исключений нарушения данных, возникающих во время выполнения.