2015-02-23 7 views
-1

У меня есть эти два класса:JPA Удалить «один» в отношении многих-к-одному

@Entity 
public class Tag { 

    @Id @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "parent") 
    private List<TagValue> values; 

    private String name; 
} 

@Entity 
public class TagValue { 

    @Id @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    private String name; 

    @ManyToOne 
    private Tag parent; 
} 

Эти два находятся в отношениях ребенка и родителя ребенок знает его родителей. Моя проблема начинается, когда я пытаюсь удалить родителя, и ребенок все еще ссылается на него. Eclipse Link сообщает мне, что я нарушаю ограничение внешнего ключа, потому что ребенок (TagValue) все еще ссылается на него. Как мне изменить свой текущий подход, чтобы иметь возможность удалить родителя, когда у ребенка все еще есть ссылка на него?

И, наконец, как я могу сообщить JPA удалить все дочерние элементы, ссылающиеся на родителя при удалении родителя? Он должен работать так. Я знаю, что было бы легче, если бы родитель знал, что это дети, используя список, но это не то, что мне нужно. Я играл с каскадом и еще много чего, но я просто не понимаю.

EDIT:

Так мне сказали, что он должен уже работать с кодом я. Так как это не так, вот пример использования, который терпит неудачу, и stacktrace ошибки.

TagValue value = new TagValue(); 
value.setName("Testvalue"); 

Tag tag = new Tag(); 
tag.setName("Testtag"); 
value.setParent(tag); 
Database.addTag(tag); 
Database.addTagValue(value); 
Database.removeTag(tag); 

Методы класса базы данных определяются следующим образом:

public static void addTag(final Tag tag) throws Exception { 
    manager.getTransaction().begin(); 
    manager.persist(tag); 
    manager.getTransaction().commit(); 
} 

public static void addTagValue(final TagValue value) throws Exception { 
    manager.getTransaction().begin(); 
    manager.persist(value); 
    manager.getTransaction().commit(); 
} 

public static void removeTag(final Tag tag) throws Exception { 
    manager.getTransaction().begin(); 
    manager.remove(tag); 
    manager.getTransaction().commit(); 
} 

StackTrace:

Примечание: Auf Schlüssel (id)=(1) wird noch aus Tabelle „tagvalue“ означает, что ключ (id)=(1) по-прежнему упоминается в таблице tagvalues.

[EL Warning]: 2015-02-24 11:12:43.785--UnitOfWork(390138887)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: org.postgresql.util.PSQLException: FEHLER: Aktualisieren oder Löschen in Tabelle „tag“ verletzt Fremdschlüssel-Constraint „fk_tagvalue_parent_id“ von Tabelle „tagvalue“ 
    Detail: Auf Schlüssel (id)=(1) wird noch aus Tabelle „tagvalue“ verwiesen. 
Error Code: 0 
Call: DELETE FROM TAG WHERE (ID = ?) 
    bind => [1 parameter bound] 
Query: DeleteObjectQuery(Tag(id=1, values=[], name=Testtag)) 
javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: org.postgresql.util.PSQLException: FEHLER: Aktualisieren oder Löschen in Tabelle „tag“ verletzt Fremdschlüssel-Constraint „fk_tagvalue_parent_id“ von Tabelle „tagvalue“ 
    Detail: Auf Schlüssel (id)=(1) wird noch aus Tabelle „tagvalue“ verwiesen. 
Error Code: 0 
Call: DELETE FROM TAG WHERE (ID = ?) 
    bind => [1 parameter bound] 
Query: DeleteObjectQuery(Tag(id=1, values=[], name=Testtag)) 
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:157) 
    at de.yabue.baka.YabueCentral.Persistence.Database.removeTag(Database.java:256) 
    at de.yabue.baka.YabueCentral.Persistence.DatabaseTest.testPersistence(DatabaseTest.java:50) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:74) 
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:673) 
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:846) 
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1170) 
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125) 
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109) 
    at org.testng.TestRunner.runWorkers(TestRunner.java:1147) 
    at org.testng.TestRunner.privateRun(TestRunner.java:749) 
    at org.testng.TestRunner.run(TestRunner.java:600) 
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:317) 
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:312) 
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:274) 
    at org.testng.SuiteRunner.run(SuiteRunner.java:223) 
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) 
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) 
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1039) 
    at org.testng.TestNG.runSuitesLocally(TestNG.java:964) 
    at org.testng.TestNG.run(TestNG.java:900) 
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:110) 
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:205) 
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:174) 
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:125) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: org.postgresql.util.PSQLException: FEHLER: Aktualisieren oder Löschen in Tabelle „tag“ verletzt Fremdschlüssel-Constraint „fk_tagvalue_parent_id“ von Tabelle „tagvalue“ 
    Detail: Auf Schlüssel (id)=(1) wird noch aus Tabelle „tagvalue“ verwiesen. 
Error Code: 0 
Call: DELETE FROM TAG WHERE (ID = ?) 
    bind => [1 parameter bound] 
Query: DeleteObjectQuery(Tag(id=1, values=[], name=Testtag)) 
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1611) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:898) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:962) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:631) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002) 
    at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:298) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.deleteObject(DatasourceCallQueryMechanism.java:210) 
    at org.eclipse.persistence.internal.queries.StatementQueryMechanism.deleteObject(StatementQueryMechanism.java:104) 
    at org.eclipse.persistence.queries.DeleteObjectQuery.executeDatabaseQuery(DeleteObjectQuery.java:218) 
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899) 
    at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798) 
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108) 
    at org.eclipse.persistence.queries.DeleteObjectQuery.executeInUnitOfWorkObjectLevelModifyQuery(DeleteObjectQuery.java:119) 
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1737) 
    at org.eclipse.persistence.internal.sessions.CommitManager.deleteAllObjects(CommitManager.java:336) 
    at org.eclipse.persistence.internal.sessions.CommitManager.deleteAllObjects(CommitManager.java:285) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1444) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531) 
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169) 
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132) 
    ... 33 more 
Caused by: org.postgresql.util.PSQLException: FEHLER: Aktualisieren oder Löschen in Tabelle „tag“ verletzt Fremdschlüssel-Constraint „fk_tagvalue_parent_id“ von Tabelle „tagvalue“ 
    Detail: Auf Schlüssel (id)=(1) wird noch aus Tabelle „tagvalue“ verwiesen. 
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103) 
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836) 
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257) 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512) 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388) 
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:334) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:890) 
    ... 59 more 

Я также пытался получить тег, я хочу, чтобы удалить из базы данных, прежде чем я удалить его, но возвращенный экземпляр не имеет элементов в values списке. Итак, моя последняя догадка заключается в том, что я должен заполнить список values сам?

+0

Вы уже делаете это с каскадом = ВСЕ. Удаление родителя должно автоматически удалять дочерние элементы. Если это не так, покажите свой код и трассировку стека исключения. –

+0

как уже говорилось выше, он уже должен работать (если вы вызываете EM.remove, не делаете удаленный пакет). Вы можете добавить Tag.values.clear() перед удалением. – Zielu

+0

@JBNizet Я добавил запрошенную вами информацию. Я уверен, что это очень тривиальная ошибка, но я очень новичок в JPA и все еще пытаюсь найти свой путь. –

ответ

1

Как и моя последняя мысль, мне пришлось заполнить список родителей. Так что теперь ошибок больше нет.

Я изменил этот метод:

public static void addTagValue(final TagValue value) throws Exception { 
    manager.getTransaction().begin(); 
    manager.persist(value); 
    manager.getTransaction().commit(); 
} 

к:

public static void addTagValue(final TagValue value) throws Exception { 
    manager.getTransaction().begin(); 
    value.getParent().getValues().add(value); 
    manager.persist(value); 
    manager.getTransaction().commit(); 
} 

И вот почему я не смотрел на это раньше: Во-первых, я как-то подумал, что mappedBy будет автоматически выполнять работу. Кроме того, я использую ломбок для создания своих сеттеров и геттеров и сделал это над аннотацией @Data. Эта аннотация генерировала все сеттеры и геттеры, а также методы toString() и hashCode(). Когда я добавил элемент в список values, метод hashCode() создал Stackoverflow, который я должен был решить первым.