Eclipselink:在嵌入式级联DELETE中删除@OneToOne

时间:2014-07-31 22:35:31

标签: java jpa eclipselink

如果@OneToOne关系本身通过JPA删除@OneToOne对象,我得到一个例外(#34;聚合对象不能独立于其所有者编写/删除/查询。#34;)和Eclipelink 2.5.2在嵌入对象中。这类似于: Using @OneToOne with Cascade.DELETE in embedded type

完整示例:

@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";
}

当我运行此操作时,我收到以下错误(&#34;无法独立于其所有者编写/删除/查询聚合对象。&#34;)

[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

如果我改为删除&#34; Bookcontent&#34;,并包含&#34; Page&#34;直接在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

1 个答案:

答案 0 :(得分:1)

实际上它正在发挥作用,但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,嵌入式关系的所有权实际上是有效的:

  

如果关系是双向的,并且包含可嵌入类的实体位于关系的拥有方,则非拥有方必须使用OneToOne批注的mappedBy元素来指定可嵌入类的关系字段或属性。必须在mappedBy元素中使用点(“。”)表示法语法来指示嵌入属性中的关系属性。

但即使正确映射了Eclipselink,也不允许删除。