java - Eclipselink:使用级联 DELETE 删除嵌入的 @OneToOne

标签 java jpa eclipselink

如果 @OneToOne 关系本身位于嵌入对象内,则通过 JPA 删除 @OneToOne 对象时,我在 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";
}

当我运行此命令时,出现以下错误(“聚合对象无法独立于其所有者进行写入/删除/查询。”)

[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

最佳答案

实际上它正在工作,但可嵌入对象不能位于关系的拥有方。我创建了一个切换所有权的示例,它运行得很好。我假设规范第 2.5 节中的以下内容适用:

Since instances of embeddable classes themselves have no persistent identity, the relationship from the referenced entity is to the entity that contains the embeddable instance(s) and not to the embeddable itself. [An entity cannot have a unidirectional relationship to the embeddable class of another entity (or itself).]

正在运行的精简示例:

@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 中关系的所有权实际上是有效的:

If the relationship is bidirectional and the entity containing the embeddable class is on the owning side of the relationship, the non-owning side must use the mappedBy element of the OneToOne annotation to specify the relationship field or property of the embeddable class. The dot (".") notation syntax must be used in the mappedBy element to indicate the relationship attribute within the embedded attribute.

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

关于java - Eclipselink:使用级联 DELETE 删除嵌入的 @OneToOne,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25070055/

相关文章:

java - 如何访问从android中的restful web服务传递的json数组?

java - 如何处理运行时错误: java. lang.NoSuchMethodError

java - 提取 PDF 注释/评论

spring - 我应该使用哪个事务管理器(JTA 与 JPA)?

java - 内部异常 : java. sql.SQLException:事务无法继续 STATUS_COMMITTED

java - 无法构建实体管理器工厂 - JPA/Hibernate

java - 如何使用 JPA(即 Hibernate EntityManager)解决 "Using Hibernate built-in connection pool (not for production use!)"

java - 使用 JPA 和 JUnit 测试时如何一致地删除内存数据库中的 H2

java - 使用 JPA 时是否可以禁用自动模式演化?

java - Windows 7中的JPA Eclipselink查询解析问题