2016-02-13 1 views
0

У меня есть следующий встраиваемый класс, который содержит @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]

я нашел несколько ссылок на этот вопрос в следующих ссылках:

Я пробовал метод @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?

ответ

1

CascadeOnDelete - это просто функция, которая указывает, что в ваших таблицах указана опция «Включить удаление каскада», чтобы JPA не нуждалась в выпуске SQL для удаления соответствующих ссылок. Этот SQL может применяться к любой ссылке, поэтому CascadeOnDelete работает с отображением коллекции элементов и любым другим отображением рефери.

Ваша проблема связана с ограничением сравнения lob в вашей базе данных, и поскольку для уникальной идентификации строк набора элементов не существует поля идентификатора, это ограничение мешает тому, как EclipseLink пытается убедиться, что он удаляет только нужные строки , Если вы хотите добавить столбец заказа к своей таблице, почему бы просто не сделать EntityEvent Entity? Или вы можете настроить EclipseLink как описано here, чтобы он использовал внешний ключ и поле orderBy или любую комбинацию полей в качестве первичного ключа для уникальной идентификации строк вместо включения поля lob.

+0

@CascadeOnDelete - это идеальное решение моей проблемы, поскольку оно обеспечивает среду, в которой все связанные вложенные элементы удаляются из таблицы COMPANY_HISTORY, когда объект компании удален, и он уменьшает SQL, необходимый для выполнения этой задачи. Однако я в замешательстве, почему это необходимо. Когда объект удаляется, вложения должны быть удалены. Почему EclipseLink просто не отправляет команду «удалить из COMPANY_HISTORY where company_id = », когда компания исключена? Почему он сравнивает все поля? Спасибо за помощь! –

Смежные вопросы