I am trying to use IdClass composite primary keys giving the following scenarios:
Here are the entity classes concerned:
Contract.java
@Entity
@IdClass(ContractPK.class)
@Table(name = "CONTRACT")
public abstract class Contract implements Serializable {
private FiscalArrangement fiscalArrangement;
private CrudeType crudeType;
public Contract() {}
public Contract(FiscalArrangement fiscalArrangement, CrudeType crudeType) {
this.fiscalArrangement = fiscalArrangement;
this.crudeType = crudeType;
}
@Id
@ManyToOne
public FiscalArrangement getFiscalArrangement() {
return fiscalArrangement;
}
public void setFiscalArrangement(FiscalArrangement fiscalArrangement) {
this.fiscalArrangement = fiscalArrangement;
}
@Id
@ManyToOne
public CrudeType getCrudeType() {
return crudeType;
}
public void setCrudeType(CrudeType crudeType) {
this.crudeType = crudeType;
}
//equals and hasCode
}
ContractPK.java
public class ContractPK implements Serializable {
private FiscalArrangement fiscalArrangement;
private CrudeType crudeType;
public ContractPK() {}
public ContractPK(FiscalArrangement fiscalArrangement, CrudeType crudeType) {
this.fiscalArrangement = fiscalArrangement;
this.crudeType = crudeType;
}
//getters and setters
}
RegularContract.java
@Entity
@DiscriminatorValue("REG")
public class RegularContract extends Contract{}
AlternativeFundingContract.java
@Entity
@DiscriminatorValue("AF")
public abstract class AlternativeFundingContract extends Contract{
private Double sharedOilRatio;
private Double terminalPeriod;
private Double terminalSharedOil;
//getters and setters
}
CarryContract.java
@Entity
@DiscriminatorValue("CA")
public class CarryContract extends AlternativeFundingContract {}
ModifiedCarryContract.java
@Entity
@DiscriminatorValue("MCA")
public class ModifiedCarryContract extends AlternativeFundingContract{}
Forecast.java
@Entity
@IdClass(ForecastPK.class)
@Table(name = "FORECAST")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "FTYPE")
public abstract class Forecast implements Serializable {
private Integer periodYear;
private Integer periodMonth;
private Contract contract;
//other non-primary properties
public Forecast() {}
@Id
public Integer getPeriodYear() {
return periodYear;
}
public void setPeriodYear(Integer periodYear) {
this.periodYear = periodYear;
}
@Id
public Integer getPeriodMonth() {
return periodMonth;
}
public void setPeriodMonth(Integer periodMonth) {
this.periodMonth = periodMonth;
}
@Id
@ManyToOne
public Contract getContract() {
return contract;
}
public void setContract(Contract contract) {
this.contract = contract;
}
//other getters and setters
}
ForecastPK.java
public class ForecastPK implements Serializable {
private Integer periodYear;
private Integer periodMonth;
private Contract contract;
//getters and setters
}
RegularForecast.java
@Entity
@DiscriminatorValue("REG")
public class RegularForecast extends Forecast {}
AlternativeFundingForecast.java
Entity
@DiscriminatorValue("AF")
public abstract class AlternativeFundingForecast extends Forecast {
//properties
}
CarryForecast.java
@Entity
@DiscriminatorValue("CA")
public class CarryForecast extends AlternativeFundingForecast{}
ModifiedCarryForecast.java
@Entity
@DiscriminatorValue("MCA")
public class ModifiedCarryForecast extends AlternativeFundingForecast{}
Controller class: JvForecastController.java
@Named(value = "jvProdController")
@SessionScoped
public class JvForecastController implements Serializable {
@Inject
private JvForecastServices forecastBean;
private Forecast currentProduction;
private Integer periodYear;
private Integer periodMonth;
private FiscalArrangement currentFiscalArrangement;
private Contract currentContract;
public JvForecastServices getForecastBean(){
return forecastBean;
}
public void currentContractChanged() throws Exception {
if (currentContract instanceof RegularContract) {
currentProduction = new RegularForecast();
} else if (currentContract instanceof CarryContract) {
currentProduction = new CarryForecast();
} else if (currentContract instanceof ModifiedCarryContract) {
currentProduction = new ModifiedCarryForecast();
} else {
throw new Exception("Undefined contract type");
}
//set primary key fields
currentProduction.setPeriodYear(periodYear);
currentProduction.setPeriodMonth(periodMonth);
currentProduction.setContract(currentContract);
}
public void productionVolumeChanged() {
getForecastBean().enrich(currentProduction);
}
}
Bean implementation class: JvForecastServicesImpl.java
@Dependent
public abstract class JvForecastServicesImpl<T extends Forecast> extends CommonServicesImpl<T> implements JvForecastServices<T>, Serializable {
public JvForecastServicesImpl(Class<T> entityClass) {
super(entityClass);
}
@Override
public T computeOpeningStock(T forecast) {
Forecast prod = getPreviousMonthProduction(forecast);
//some code
return forecast;
}
@Override
public T getPreviousMonthProduction(T forecast) {
int month = forecast.getPeriodMonth();
int year = forecast.getPeriodYear();
Contract cs = forecast.getContract();
Contract contract = null;
if (cs instanceof RegularContract) {
contract = new RegularContract(cs.getFiscalArrangement(), cs.getCrudeType());
} else if (cs instanceof CarryContract) {
contract = new CarryContract(cs.getFiscalArrangement(), cs.getCrudeType());
} else if (contract instanceof ModifiedCarryContract) {
contract = new ModifiedCarryContract(cs.getFiscalArrangement(), cs.getCrudeType());
}
FiscalPeriod prevFp = getPreviousFiscalPeriod(year, month);
T f = find(new ForecastPK(prevFp.getYear(), prevFp.getMonth(), contract));
return f;
}
}
CommonServicesImpl.java
public abstract class CommonServicesImpl<T> extends AbstractCrudServicesImpl<T> implements CommonServices<T> {}
Implementation of the find() method in AbstractCrudServicesImpl.java
public abstract class AbstractCrudServicesImpl<T> implements AbstractCrudServices<T> {
protected final Class<T> entityClass;
public AbstractCrudServicesImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
//some CRUD methods
@Override
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
}
When the following line of code in JvForecastServicesImpl class executes:
T f = find(new ForecastPK(prevFp.getYear(), prevFp.getMonth(), contract));
I get the error message:
10:24:59,492 INFO [org.hibernate.event.internal.DefaultLoadEventListener] (default task-42) HHH000327: Error performing load command : org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.nnpcgroup.cosm.entity.contract.Contract 10:24:59,497 ERROR [org.jboss.as.ejb3.invocation] (default task-42) WFLYEJB0034: EJB Invocation failed on component RegularForecastBean for method public abstract java.lang.Object com.nnpcgroup.cosm.ejb.CommonServices.enrich(java.lang.Object): javax.ejb.EJBException: java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.nnpcgroup.cosm.entity.contract.Contract at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:187) at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:277) at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:327) at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:239) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:66) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356) at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:636) at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:356) at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:195) at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:185) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:73) at com.nnpcgroup.cosm.ejb.forecast.jv.JvRegularForecastServices$$$view23.enrich(Unknown Source) at com.nnpcgroup.cosm.controller.JvForecastController.productionVolumeChanged(JvForecastController.java:233) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.sun.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:181) at com.sun.el.parser.AstValue.invoke(AstValue.java:289) at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304) at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40) at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40) at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) at com.sun.faces.facelets.tag.jsf.core.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxHandler.java:459) at javax.faces.event.AjaxBehaviorEvent.processListener(AjaxBehaviorEvent.java:113) at javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.java:106) at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:805) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.DisableCacheHandler.handleRequest(DisableCacheHandler.java:33) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:793) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.nnpcgroup.cosm.entity.contract.Contract at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1689) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1619) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1106) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1033) at org.jboss.as.jpa.container.AbstractEntityManager.find(AbstractEntityManager.java:213) at com.nnpcgroup.cosm.ejb.impl.AbstractCrudServicesImpl.find(AbstractCrudServicesImpl.java:44) at com.nnpcgroup.cosm.ejb.forecast.jv.impl.JvForecastServicesImpl.getPreviousMonthProduction(JvForecastServicesImpl.java:204) at com.nnpcgroup.cosm.ejb.forecast.jv.impl.JvForecastServicesImpl.computeOpeningStock(JvForecastServicesImpl.java:47) at com.nnpcgroup.cosm.ejb.forecast.jv.impl.JvForecastServicesImpl.enrich(JvForecastServicesImpl.java:112) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:437) at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.doMethodInterception(Jsr299BindingsInterceptor.java:82) at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.processInvocation(Jsr299BindingsInterceptor.java:93) at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.jpa.interceptor.SBInvocationInterceptor.processInvocation(SBInvocationInterceptor.java:47) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:437) at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:64) at org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:83) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:21) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:52) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.component.pool.PooledInstanceInterceptor.processInvocation(PooledInstanceInterceptor.java:51) at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340) at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:275) ... 86 more
JPA calls this type of composite primary key a "derived identity".
You will need to change your IdClass
es. ContractPK
should look something like this (assuming FiscalArrangement
and CrudeType
have simple primary keys):
public class ContractPK implements Serializable {
private Integer fiscalArrangement;
private Integer crudeType;
...
}
Note the attribute names match the Entity
's @Id
attribute names, but the types must match the types of the target Entity
s' primary keys.
If the target Entity
s use @IdClass
es, ContractPK
should look something like this:
public class ContractPK implements Serializable {
private FiscalArrangementPK fiscalArrangement;
private CrudeTypePK crudeType;
...
}
Note the attribute types are now IdClass
es.
Likewise, ForecastPK
should look something like this:
public class ForecastPK implements Serializable {
private Integer periodYear;
private Integer periodMonth;
private Integer contract;
...
}
or this:
public class ForecastPK implements Serializable {
private Integer periodYear;
private Integer periodMonth;
private ContractPK contract;
...
}
Derived identities are discussed in the JPA 2.1 spec, section 2.4.1.