У меня есть следующий встраиваемый класс, который содержит @Lob:Почему EclipseLink поддерживает @CascadeOnDelete с @ElementCollection?
@Embeddable
public class EntityState {
private Integer version;
@Lob
@XmlJavaTypeAdapter(CharArrayAdapter.class)
private char[] xmlState;
...
}
Я также иметь следующий встраиваемый класс, который содержит выше встраиваемый:
@Embeddable
public class EntityEvent {
@NotNull
private String note;
private EntityState entityState;
...
}
Наконец, у меня есть много классов сущностей, которые содержат свойство, называемое историей, которое является списком EntityEvents. Ниже приведен пример:
@Entity
public class Company {
@NotNull
@ElementCollection
private List<EntityEvent> history;
...
}
Когда я раскрываю мое приложение в GlassFish 4.1 EclipseLink создает следующие таблицы в моей базе данных Derby 10.11.1.1:
- КОМПАНИЯ
- COMPANY_HISTORY
Когда я создаю новую компанию, мое приложение создает EntityEvent и добавляет EntityEvent к истории компании.
Когда я изменить компанию, мое приложение делает следующее:
- Создает объект EntityState и устанавливает свойство xmlState к XML-представлению неизмененной сущности.
- Создает объект EntityEvent, содержащий указанный выше EntityState.
- Добавляет EntityEvent к истории компании.
Проблема заключается в том, что при попытке удалить объект, который имеет свою историю с несколько EntityEvents я получаю следующее сообщение об ошибке:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLSyntaxErrorException: Comparisons between 'CLOB (UCS_BASIC)' and 'CLOB (UCS_BASIC)' are not supported. Types must be comparable. String types must also have matching collation. If collation does not match, a possible solution is to cast operands to force them to the default collation (e.g. SELECT tablename FROM sys.systables WHERE CAST(tablename AS VARCHAR(128)) = 'T1')
Error Code: 20000 Call: DELETE FROM Company_HISTORY WHERE ((((((((((CHANGES = ?) AND (CLIENTTYPE = ?)) AND (CREATED = ?)) AND (IPADDRESS = ?)) AND (NOTE = ?)) AND (TYPE = ?)) AND (VERSION = ?)) AND (XMLSTATE = ?)) AND (CREATER_ID = ?)) AND (Company_ID = ?)) bind => [10 parameters bound]
я нашел несколько ссылок на этот вопрос в следующих ссылках:
- Hibernate - @ElementCollection - Strange delete/insert behavior
- http://eclipse.1072660.n5.nabble.com/Customizing-delete-calls-before-updating-a-ElementCollection-td7312.html
Я пробовал метод @OrderColumn, описанный в вышеупомянутой статье stackoverflow, но это не сработало в EclipseLink.
Решение, которое работает для меня, чтобы добавить EclipseLink нестандартной @CascadeOnDelete аннотации к моему лицу, как показано ниже:
@Entity
public class Company {
@NotNull
@ElementCollection
@CascadeOnDelete
private List<EntityEvent> history;
...
}
После выполнения этого изменения и восстановления моей базы данных, мой COMPANY_HISTORY таблица имеет новое определение:
- Без @CascadeOnDelete
- ALTER TABLE COMPANY_HISTORY ADD CONSTRAINT CMPNYHISTORYCMPNYD FO REIGN KEY (COMPANY_ID) ССЫЛКИ КОМПАНИИ (ID);
- С @CascadeOnDelete
- ALTER TABLE COMPANY_HISTORY ADD CONSTRAINT CMPNYHISTORYCMPNYD FOREIGN KEY (company_id) СПИСОК ЛИТЕРАТУРЫ КОМПАНИ (ID) ON DELETE CASCADE;
Решение моей проблемы удивило меня, потому что кажется повторяющимися. Я понимаю, что JPA должна удалить все вложения, связанные с сущностью при удалении сущности. Тот факт, что EclipseLink имеет эту нестандартную аннотацию, как описано в следующей ссылке, заставляет меня думать, что EclipseLink имеет ошибку, и вместо исправления ошибки была создана новая аннотация @CascadeOnDelete, так что ошибка будет покрыта функциональностью каскадного удаления баз данных.
Так что мой вопрос, почему. Почему EclipseLink поддерживает @CascadeOnDelete с @ElementCollection?
@CascadeOnDelete - это идеальное решение моей проблемы, поскольку оно обеспечивает среду, в которой все связанные вложенные элементы удаляются из таблицы COMPANY_HISTORY, когда объект компании удален, и он уменьшает SQL, необходимый для выполнения этой задачи. Однако я в замешательстве, почему это необходимо. Когда объект удаляется, вложения должны быть удалены. Почему EclipseLink просто не отправляет команду «удалить из COMPANY_HISTORY where company_id =», когда компания исключена? Почему он сравнивает все поля? Спасибо за помощь! –