У меня есть веб-приложение JPA 2 (Struts 2, Hibernate 4 как реализация только JPA).
Текущее требование состоит в том, чтобы добавить (не id) числовое последовательное поле, заполненное только для определенных строк, к существующей сущности. При вставке новой строки, основанной на определенном условии, мне нужно установить новое поле в its highest value + 1
или NULL
.
Например:
ID NEW_FIELD DESCRIPTION
--------------------------------
1 1 bla bla
2 bla bla <--- unmatched: not needed here
3 bla bla <--- unmatched: not needed here
4 2 bla bla
5 3 bla bla
6 4 bla bla
7 bla bla <--- unmatched: not needed here
8 5 bla bla
9 bla bla <--- unmatched: not needed here
10 6 bla bla
В хорошем старом SQL это будет что-то вроде:
INSERT INTO myTable (
id,
new_field,
description
) VALUES (
myIdSequence.nextVal,
(CASE myCondition
WHEN true
THEN myNewFieldSequence.nextVal
ELSE NULL
END),
'Lorem Ipsum and so on....'
)
Но я не знаю, как это сделать с JPA 2.
Я знаю, что могу определить методы обратных вызовов, но JSR-000317 Спецификация сохранения для Eval 2.0 Eval препятствует некоторым конкретным операциям изнутри:
3.5 Прослушиватели и методы обратного вызова
- Обратные вызовы Lifecycle могут вызывать JNDI, JDBC, JMS и enterprise beans.Суб >
- В общем, метод жизненного цикла переносимого приложения не должен вызывать операции EntityManager или Query, доступ к другому объекту экземпляры или изменять отношения в пределах одного и того же контекст. [43] Метод обратного вызова жизненного цикла может изменять не связанное с состоянием объекта, на который он вызывается.[43] Семантика таких операций может быть стандартизирована в будущем выпуске этой спецификации.
Подведение итогов, да JDBC (!) и EJB, нет для EntityManager и других объектов.
ИЗМЕНИТЬ
Я пытаюсь найти решение, описанное в ответе от @anttix, но я устраняю некоторые проблемы, поэтому, пожалуйста, исправьте меня, где я ошибаюсь.
Таблица
MyTable
-------------------------
ID number (PK)
NEW_FIELD number
DESCRIPTION text
Основной объект
@Entity
@Table(name="MyTable")
public class MyEntity implements Serializable {
@Id
@SequenceGenerator(name="seq_id", sequenceName="seq_id", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_id")
private Long id;
@OneToOne(cascade= CascadeType.PERSIST)
private FooSequence newField;
private String description
/* Getters and Setters */
}
Субъект
@Entity
public class FooSequence {
@Id
@SequenceGenerator(name="seq_foo", sequenceName="seq_foo", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_foo")
private Long value;
/* Getter and Setter */
}
DAO
myEntity.setNewField(new FooSequence());
entityManager.persist(myEntity);
Exception
Вызвано: javax.transaction.RollbackException: ARJUNA016053: Не удалось выполнить транзакцию.
[...]
Вызвано: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: ERROR: отношения "new_field" не существует
[...]
Вызвано: org.hibernate.exception.SQLGrammarException: ERROR: отношения "new_field" не существует
[...]
Вызвано: org.postgresql.util.PSQLException: ОШИБКА: отношения "new_field" не существует
Что я делаю неправильно? Я новичок в JPA 2, и я никогда не использовал объект, не связанный с физической таблицей... этот подход для меня совершенно незначителен.
Думаю, мне нужно где-то поместить определение @Column
: как JPA, возможно, знает, что столбец newField
(сопоставленный ImprovedNamingStrategy с new_field
на база данных) извлекается через свойство value
объекта FooSequence
?
Некоторые фрагменты головоломки отсутствуют.
EDIT
Как указано в комментариях, это persistence.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="MyService" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/myDS</jta-data-source>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.ejb.naming_strategy"
value="org.hibernate.cfg.ImprovedNamingStrategy"/>
<property name="hibernate.query.substitutions"
value="true 'Y', false 'N'"/>
<property name="hibernate.show_sql" value="true" />
<property name="format_sql" value="true" />
<property name="use_sql_comments" value="true" />
</properties>
</persistence-unit>
</persistence>