Eclipselink:删除@OneToOne内部嵌入级联DELETE



当通过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也不允许删除

最新更新