当通过JPA删除@OneToOne对象时,如果@OneToOne关系本身在嵌入对象内,则使用Eclipelink 2.5.2得到一个异常("聚合对象不能独立于其所有者进行写入/删除/查询")。这类似于:使用@OneToOne与Cascade。删除嵌入类型
完整的示例:
@Entity
public class Book {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
protected int id;
public String title = "foo";
// @OneToMany(cascade={CascadeType.ALL})
// public List<Page> pages = new ArrayList<Page>(); // if pages are directly inside the book (instead of in the embedded BookContext), this example works fine
@Embedded
public BookContent bookContent;
public Book() {
bookContent = new BookContent();
// pages.add(new Page()); // if this is used instead of bookContent, then it works
}
public static void main(String[] args) {
try {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Book");
EntityManager em = emf.createEntityManager();
Book book = new Book();
em.getTransaction().begin();
em.persist(book);
em.getTransaction().commit();
em.getTransaction().begin();
Query query = em.createQuery("Select g from Book g"); // of course in this example the query would not be necessary
List<Book> results = query.getResultList();
for (Book bookToRemove : results){
em.remove(bookToRemove);
}
em.getTransaction().commit();
em.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
@Embeddable
public class BookContent {
@OneToOne(cascade={CascadeType.ALL})
public Page page;
public String bookdContentID = "1";
public BookContent() {
page = new Page();
}
}
@Entity
public class Page {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
protected int id;
public String text = "test";
}
当我运行这个时,我得到以下错误("聚合对象不能独立于其所有者进行写入/删除/查询。")
[EL Fine]: sql: 2014-07-31 14:51:41.157--ClientSession(907509627)--Connection(2114173229)--Thread(Thread[main,5,main])--DELETE FROM BOOK_PAGE WHERE (Book_ID = ?)
bind => [1]
[EL Finest]: query: 2014-07-31 14:51:41.159--UnitOfWork(811619113)--Thread(Thread[main,5,main])--Execute query DeleteObjectQuery(Page@577a863d)
[EL Finest]: query: 2014-07-31 14:51:41.159--UnitOfWork(811619113)--Thread(Thread[main,5,main])--Execute query DeleteObjectQuery(BookContent@4b9f8b6c)
[EL Warning]: 2014-07-31 14:51:41.164--UnitOfWork(811619113)--Thread(Thread[main,5,main])--Local Exception Stack:
Exception [EclipseLink-6002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.QueryException
Exception Description: Aggregated objects cannot be written/deleted/queried independently from their owners.
Descriptor: [RelationalDescriptor(BookContent --> [])]
Query: DeleteObjectQuery(BookContent@4b9f8b6c)
at org.eclipse.persistence.exceptions.QueryException.aggregateObjectCannotBeDeletedOrWritten(QueryException.java:250)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.prepare(ObjectLevelModifyQuery.java:205)
at org.eclipse.persistence.queries.DeleteObjectQuery.prepare(DeleteObjectQuery.java:327)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:661)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:613)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:867)
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.queries.DeleteObjectQuery.executeDatabaseQuery(DeleteObjectQuery.java:194)
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:290)
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)
at Book.main(Book.java:53)
[EL Finer]: transaction: 2014-07-31 14:51:41.165--ClientSession(907509627)--Connection(2114173229)--Thread(Thread[main,5,main])--rollback transaction
[EL Finest]: connection: 2014-07-31 14:51:41.166--ServerSession(228859333)--Connection(2114173229)--Thread(Thread[main,5,main])--Connection released to connection pool [default].
[EL Finer]: transaction: 2014-07-31 14:51:41.166--UnitOfWork(811619113)--Thread(Thread[main,5,main])--release unit of work
[EL Finer]: connection: 2014-07-31 14:51:41.166--ClientSession(907509627)--Thread(Thread[main,5,main])--client released
javax.persistence.RollbackException: Exception [EclipseLink-6002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.QueryException
Exception Description: Aggregated objects cannot be written/deleted/queried independently from their owners.
Descriptor: [RelationalDescriptor(BookContent --> [])]
Query: DeleteObjectQuery(BookContent@4b9f8b6c)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:157)
at Book.main(Book.java:53)
Caused by: Exception [EclipseLink-6002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.QueryException
Exception Description: Aggregated objects cannot be written/deleted/queried independently from their owners.
Descriptor: [RelationalDescriptor(BookContent --> [])]
Query: DeleteObjectQuery(BookContent@4b9f8b6c)
at org.eclipse.persistence.exceptions.QueryException.aggregateObjectCannotBeDeletedOrWritten(QueryException.java:250)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.prepare(ObjectLevelModifyQuery.java:205)
at org.eclipse.persistence.queries.DeleteObjectQuery.prepare(DeleteObjectQuery.java:327)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:661)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:613)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:867)
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.queries.DeleteObjectQuery.executeDatabaseQuery(DeleteObjectQuery.java:194)
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:290)
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)
... 1 more
如果我删除"Bookcontent",并将"Page"对象直接包含在Book对象中,则一切正常:
[EL Fine]: sql: 2014-07-31 15:10:45.241--ClientSession(1901887672)--Connection(2055970986)--Thread(Thread[main,5,main])--DELETE FROM BOOK_PAGE WHERE (Book_ID = ?)
bind => [1]
[EL Finest]: query: 2014-07-31 15:10:45.242--UnitOfWork(404057375)--Thread(Thread[main,5,main])--Execute query DeleteObjectQuery(Page@7a9a042)
[EL Fine]: sql: 2014-07-31 15:10:45.243--ClientSession(1901887672)--Connection(2055970986)--Thread(Thread[main,5,main])--DELETE FROM PAGE WHERE (ID = ?)
bind => [1]
[EL Finest]: query: 2014-07-31 15:10:45.245--UnitOfWork(404057375)--Thread(Thread[main,5,main])--Execute query DeleteObjectQuery(Book@26af1a93)
[EL Fine]: sql: 2014-07-31 15:10:45.246--ClientSession(1901887672)--Connection(2055970986)--Thread(Thread[main,5,main])--DELETE FROM BOOK WHERE (ID = ?)
bind => [1]
[EL Finer]: transaction: 2014-07-31 15:10:45.247--ClientSession(1901887672)--Connection(2055970986)--Thread(Thread[main,5,main])--commit transaction
[EL Finest]: connection: 2014-07-31 15:10:45.248--ServerSession(686104144)--Connection(2055970986)--Thread(Thread[main,5,main])--Connection released to connection pool [default].
[EL Finer]: transaction: 2014-07-31 15:10:45.248--UnitOfWork(404057375)--Thread(Thread[main,5,main])--end unit of work commit
[EL Finer]: transaction: 2014-07-31 15:10:45.248--UnitOfWork(404057375)--Thread(Thread[main,5,main])--resume unit of work
[EL Finer]: transaction: 2014-07-31 15:10:45.249--UnitOfWork(404057375)--Thread(Thread[main,5,main])--release unit of work
[EL Finer]: connection: 2014-07-31 15:10:45.249--ClientSession(1901887672)--Thread(Thread[main,5,main])--client released
实际上它正在工作,但Embeddable不能在关系的拥有方。我创建了一个转换所有权的例子,它运行得很好。我假设规范第2.5节中的下列语句适用:
自实例可嵌入类本身没有持久的标识,从到被引用的实体的关系是指向包含可嵌入实例的实体,而不是指向可嵌入本身。[一个实体不能与另一个实体(或其自身)的可嵌入类有单向关系]
正在工作的剥离示例:
@Embeddable
public class BookContent {
@OneToOne(mappedBy="book",cascade={CascadeType.ALL})
Page page;
}
@Entity
public class Book {
@Id @GeneratedValue int id;
@Embedded
public BookContent bookContent;
}
@Entity
public class Page {
@Id @GeneratedValue int id;
@OneToOne
Book book;
}
注意:现在Page
是关系的所有者。
我假设有一页书不是我们通常看到的,所以我也检查了@OneToMany
工作正常。
// BookContent
@OneToMany(mappedBy="book",cascade={CascadeType.ALL})
List<Page> page;
// Page
@ManyToOne
Book book;
根据API Javadoc:
, embeddable中关系的所有权实际上是有效的。如果关系是双向的,并且包含可嵌入类的实体位于关系的拥有方,则非拥有方必须使用OneToOne注释的mapappedby元素来指定可嵌入类的关系字段或属性。必须在mapappedby元素中使用点(".")表示法语法来指示嵌入属性中的关系属性。
但是即使正确映射了Eclipselink也不允许删除