JPA не может удалить @OneToOne, если определено @JoinTable
У меня есть забавная "проблема", то есть явление.
Быстрая информация:
_BaseEntity
это@MappedSuperclass
который обрабатывает ID, hashCode, equals, CompareTo и т. д. и отлично работает во всех моих проектах)- Я использую Payara (EclipseLink) на БД MySQL
@Expose
тег GSON- Я нашел много похожих тем, но ни один не отвечает на мой вопрос, или не делает различий с / без
@JoinTable
или получить ответ в решающей манере... - отношение одностороннее, т.е. только из
Thema->TopThema
и явно НЕТTopThema->Thema
ПРИМЕР РАБОТЫ Когда у меня есть такая сущность
@Entity
@Table(name = Thema.TABLE_NAME)
public class Thema extends _BaseEntity {
static public final String TABLE_NAME = UEntity.TABLE_PREFIX + "Thema";
@Expose @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private TopThema topThema;
}
Я могу просто EntityManager.remove() это.
,
ПРИМЕР НЕ РАБОТАЕТ:
Но если это определено так
@Entity
@Table(name = Thema.TABLE_NAME)
public class Thema extends _BaseEntity {
static public final String TABLE_NAME = UEntity.TABLE_PREFIX + "Thema";
@Expose @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinTable(name = TABLE_NAME + "_topThema")
private TopThema topThema;
}
(имеющий промежуточную таблицу "GP_Thema_topThema", как определено @JoinTable(name = TABLE_NAME + "_topThema")
тогда EntityManager.remove() генерирует исключение:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Невозможно удалить или обновить родительскую строку: ограничение внешнего ключа не выполняется (
test_PT_local
,GP_Thema_topThema
, ОГРАНИЧЕНИЕFK_GP_Thema_topThema_topThema_ID
ИНОСТРАННЫЙ КЛЮЧ (topThema_ID
) РЕКОМЕНДАЦИИGP_TopThema
(ID
))
Я знаю, что это не имеет особого смысла, чтобы иметь дополнительный @JoinTable
используется, когда ссылка также может быть просто сохранена внутри "GP_Thema" как "GP_Thema". "TOPTHEMA_ID". Плюс: оба определения сущностей одинаково хорошо работают на стороне Java.
Но из интереса: почему JPA не может удалить запись в @JoinTable
GP_Thema_topThema
хотя я поставил cascade = CascadeType.ALL
а также orphanRemoval = true
?
Обновление: и из-за @JoinTable
Я тоже не могу - сначала удалить TopThema, потом Thema (кидает MySQLIntegrityConstraintViolationException
на TopThema удалить)
- det Thema.topThema = null, затем обновить (выдает MySQLIntegrityConstraintViolationException
снова)
2 ответа
Не JPA не может удалить объект, но фактическую базу данных. То, что вы ищете, - это отложенное ограничение, а в MySQL это невозможно.
Mysql документы, касающиеся отсрочиваемых ограничений здесь
Как и MySQL в целом, в операторе SQL, который вставляет, удаляет или обновляет много строк, InnoDB проверяет ограничения UNIQUE и FOREIGN KEY построчно. При выполнении проверок внешнего ключа InnoDB устанавливает общие блокировки на уровне строк для дочерних или родительских записей, которые он должен просматривать. InnoDB немедленно проверяет ограничения внешнего ключа; проверка не откладывается до фиксации транзакции. Согласно стандарту SQL, поведение по умолчанию должно быть отложено. То есть ограничения проверяются только после обработки всего оператора SQL. Пока InnoDB не реализует отложенную проверку ограничений, некоторые вещи невозможны, например, удаление записи, которая ссылается на себя с использованием внешнего ключа
Рассматривали ли вы переход на PostgreSQL?
Отложенные ограничения не проверяются до фиксации транзакции
Как примечание, вы можете удалить свой Thema
с помощью JPA и MySQL ... Для этого вам нужно просто объявить внешние ключи вашего @JoinTable
(GP_Thema_topThema) как "ON DELETE CASCADE" ...
Пример:
CREATE TABLE GP_Thema_topThema(
thema_ID integer NOT NULL,
topThema_ID integer NOT NULL,
FOREIGN KEY (thema_ID)
REFERENCES thema (id)
ON DELETE CASCADE,
FOREIGN KEY (topThema_ID)
REFERENCES top_thema(id)
ON DELETE CASCADE
)
Таким образом, если база данных получает команду удаления Thema
субъект, то любой связанный GP_Thema_topThema
сущности (или кортежи) также будут удалены...