JPA - 将对象级联保存到由id映射的数据库

时间:2016-01-08 13:54:08

标签: java hibernate postgresql jpa

我将 A 对象保存为非 b 属性到数据库时遇到问题。 我设置级联到所有,所以我希望它也会保存 B 对象。如果我尝试使用 entityManager.merge(a)方法,对象会保存而不会出错,但是当我调用简单的'选择'在数据库上检查数据库中的记录是否正确我看到table_a和table_b中相应行的 id 是不同的。我应该如何通过管理 A 对象来修复我的代码 B 对象也会正确保存?

JPA提供者:Hibernate

Darabase:PostgreSQL

我的代码:

@Entity
@Table(name = "table_a")
public class A {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @JoinColumn(name = "id", referencedColumnName = "id")
    @OneToOne(cascade = {CascadeType.ALL}, orphanRemoval = true)
    private B b;

    ...
}

@Entity
@Table(name = "table_b")
public class B {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    ...
}

我的表格:

create table table_a (
    id BIGSERIAL PRIMARY KEY,
    ...
);

create table table_b (
    id BIGSERIAL PRIMARY KEY REFERENCES table_a(id),
    ...
);

[在Adam的Michalik回答之后编辑]

我目前的代码:

@Entity
@Table(name = "table_a")
public class A {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @OneToOne(mappedBy = "a", cascade = {CascadeType.ALL})
    private B b;

    ...
}

@Entity
@Table(name = "table_b")
public class B {

    @Id
    @JoinColumn(name = "id", referencedColumnName = "id")
    @OneToOne(cascade = {CascadeType.ALL})
    private A a;

    ...
}

我的表格:

create table table_a (
    id BIGSERIAL PRIMARY KEY,
    ...
);

create table table_b (
    id BIGINT PRIMARY KEY REFERENCES table_a(id),
    ...
);

现在我得到这个异常opon调用entityManager.merge(a):

Exception in thread "main" javax.ejb.EJBTransactionRolledbackException
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:163)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:253)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:342)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:239)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:95)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:439)
    at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
    at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185)
    at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:182)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:73)
...
Caused by: java.lang.NullPointerException
    at org.hibernate.type.descriptor.java.AbstractTypeDescriptor.extractHashCode(AbstractTypeDescriptor.java:84)
    at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:216)
    at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:220)
    at org.hibernate.type.EntityType.getHashCode(EntityType.java:391)
    at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:258)
    at org.hibernate.engine.spi.EntityKey.generateHashCode(EntityKey.java:76)
    at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:71)
    at org.hibernate.internal.AbstractSessionImpl.generateEntityKey(AbstractSessionImpl.java:327)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:166)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:886)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:868)
    at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:277)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:460)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:255)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:189)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:85)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:876)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:858)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:863)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1196)
    at org.jboss.as.jpa.container.AbstractEntityManager.merge(AbstractEntityManager.java:566)

1 个答案:

答案 0 :(得分:2)

这里有一些问题:

  1. 在实体模型中,您具有从A到B的单向一对一关系。这会将外键置于A中的B.但是在DB架构中,您已将外键置于B中的A因此,您需要在实体模型中创建双向关系,或者将FK移动到表A。
  2. 虽然table_b.id引用table_a.id,但您将这两列标记为BIGSERIAL,这两列将自动生成两者。但是只应该生成一个而另一个应该复制引用的值。
  3. 解决上述问题后,您需要正确映射&#34;派生身份&#34;。请参阅我的回答here,这与您的情况相符。