"org.hibernate.TypeMismatchException: Provided id of the wrong type" 将@OneToOne 用于双向关系时
"org.hibernate.TypeMismatchException: Provided id of the wrong type" when using @OneToOne for a bi-directional relation
当两个 classes 中的复合主键相同时,我无法成功使用 @OneToOne:
@Entity
public class One implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private OnePK onePK;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "one")
private Two two;
//... constructors, getters and setters
}
@Entity
public class Two implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private TwoPK twoPK;
@JoinColumns({
@JoinColumn(name = "P_ID", referencedColumnName = "P_ID", insertable = false, updatable = false),
@JoinColumn(name = "L_ID", referencedColumnName = "L_ID", insertable = false, updatable = false)})
@OneToOne(optional = false)
private One one;
//... constructors, getters and setters
}
@Embeddable
public class OnePK implements Serializable {
@Basic(optional = false)
@Column(name = "P_ID")
private BigInteger dId;
@Basic(optional = false)
@Column(name = "L_ID")
private BigInteger lId;
//... constructors, getters and setters
}
@Embeddable
public class TwoPK implements Serializable {
@Basic(optional = false)
@Column(name = "P_ID")
private BigInteger dId;
@Basic(optional = false)
@Column(name = "L_ID")
private BigInteger lId;
//... constructors, getters and setters
}
当我按原样使用上面的源代码时,我得到:
12:56:04,021 WARNING [org.apache.cxf.phase.PhaseInterceptorChain]
(default task-83) Application
{http://services.webservices.*****.******.com/}ObjectManagerService#{http://services.webservices.*****.******.com/}getAllObjects
has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault:
java.lang.IllegalArgumentException:
org.hibernate.TypeMismatchException: Provided id of the wrong type for
class com.******.*****..********.Two. Expected: class
com.******.*****..********.TwoPK, got class
com.******.*****.**.********.OnePK at
org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162)
at
org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.createFault(AbstractJAXWSMethodInvoker.java:267)
at
当我使用相同的 class (OnePK) 作为两个 classes(一和二)的主键时,我得到:
11:44:35,735 WARNING [org.apache.cxf.phase.PhaseInterceptorChain]
(default task-83) Interceptor for
{http://services.webservices.*****.******.com/}ObjectManagerService#{http://services.webservices.*****.******.com/}getAllObjects
has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault:
Marshalling Error: A cycle is detected in the object graph. This will
cause infinitely deep XML : One[ onePK=OnePK[ dId=3151, lId=426 ] ] ->
Two[ twoPK=OnePK[ dId=3151, lId=426 ] ] -> One[ onePK=OnePK[ dId=3151,
lId=426 ] ] at
org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:266)
at
org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:238)
at
org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:118)
at
使用@PrimaryKeyJoinColumns 没有帮助,我使用了this answer and this tutorial, I got the same error messages. Using @MapsId didn't help, I got "org.hibernate.exception.GenericJDBCException: could not prepare statement". Maybe the root cause is this unfixed bug of Hibernate。我发现的唯一解决方法是删除第一次出现的 @OneToOne 和 class "One" 中的字段 "two" 但是 One 的实例包含的 Two 的实例没有当我删除 One 的这个实例时 longer 被删除,这就是我使用 CascadeType.ALL.
的原因
此 JPA 源代码由 Netbeans 8 自动生成。我有点不知所措。有没有办法让它正常工作?这真的是 Hibernate 的限制吗?是否有另一种 JPA 实现可以正确处理这种情况?
我认为问题出在您的 @JoinColumn
映射中使用的 name
属性,在您的 Two
class 中,其中用于 name
与 referencedColumnName
.
相同
事实上 Two
class 已经从其 TwoPk
class 中嵌入了 P_ID
和 L_ID
属性,因此当您使用相同的名称 name = "P_ID"
和 name = "L_ID"
,你不能映射两个 class 因为这些属性已经在这个 Entity
中所以你应该指定不同的名称:
@JoinColumns({
@JoinColumn(name = "OneP_ID", referencedColumnName = "P_ID", insertable = false, updatable = false),
@JoinColumn(name = "OneL_ID", referencedColumnName = "L_ID", insertable = false, updatable = false)})
@OneToOne(optional = false)
private One one;
注:
如果您对 PK 使用两个不同的 classes,为什么在两个 classes 中使用相同的属性名称,最好在 [=] 中使用不同的名称来标识它们23=] 和 TwoPk
为:
分别oneDId
和oneLId
在你的OnePk
class和twoDId
和twoLId
在你的TwoPk
class, 这将使事情变得更好,更容易阅读、识别和映射。
起初,我通过调用 this method 增加了 Oracle UCP 中的 TTL 连接超时,以摆脱 GenericJDBCException
。某些请求的执行时间太长,而允许保持连接使用的时间太短。
其次,我使用相同的 class 命名为 OnePK 作为 classes One 和 Two 的主键。
第三,我将@XmlTransient
添加到方法getOne()之前的两个class中,以修复XML序列化中的循环。
第四,我修改了我的管理器,以便他们调用 Two.setOne(final One one) 以便在不使用 Web 服务的情况下为调用持久层的源代码公开完整的对象(Two 的实例)。
最后,我通过 @MapsId
.
修复了一些类似的情况,但主键更简单,仅由一列组成
当两个 classes 中的复合主键相同时,我无法成功使用 @OneToOne:
@Entity
public class One implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private OnePK onePK;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "one")
private Two two;
//... constructors, getters and setters
}
@Entity
public class Two implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private TwoPK twoPK;
@JoinColumns({
@JoinColumn(name = "P_ID", referencedColumnName = "P_ID", insertable = false, updatable = false),
@JoinColumn(name = "L_ID", referencedColumnName = "L_ID", insertable = false, updatable = false)})
@OneToOne(optional = false)
private One one;
//... constructors, getters and setters
}
@Embeddable
public class OnePK implements Serializable {
@Basic(optional = false)
@Column(name = "P_ID")
private BigInteger dId;
@Basic(optional = false)
@Column(name = "L_ID")
private BigInteger lId;
//... constructors, getters and setters
}
@Embeddable
public class TwoPK implements Serializable {
@Basic(optional = false)
@Column(name = "P_ID")
private BigInteger dId;
@Basic(optional = false)
@Column(name = "L_ID")
private BigInteger lId;
//... constructors, getters and setters
}
当我按原样使用上面的源代码时,我得到:
12:56:04,021 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] (default task-83) Application {http://services.webservices.*****.******.com/}ObjectManagerService#{http://services.webservices.*****.******.com/}getAllObjects has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: java.lang.IllegalArgumentException: org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.******.*****..********.Two. Expected: class com.******.*****..********.TwoPK, got class com.******.*****.**.********.OnePK at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162) at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.createFault(AbstractJAXWSMethodInvoker.java:267) at
当我使用相同的 class (OnePK) 作为两个 classes(一和二)的主键时,我得到:
11:44:35,735 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] (default task-83) Interceptor for {http://services.webservices.*****.******.com/}ObjectManagerService#{http://services.webservices.*****.******.com/}getAllObjects has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: Marshalling Error: A cycle is detected in the object graph. This will cause infinitely deep XML : One[ onePK=OnePK[ dId=3151, lId=426 ] ] -> Two[ twoPK=OnePK[ dId=3151, lId=426 ] ] -> One[ onePK=OnePK[ dId=3151, lId=426 ] ] at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:266) at org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:238) at org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:118) at
使用@PrimaryKeyJoinColumns 没有帮助,我使用了this answer and this tutorial, I got the same error messages. Using @MapsId didn't help, I got "org.hibernate.exception.GenericJDBCException: could not prepare statement". Maybe the root cause is this unfixed bug of Hibernate。我发现的唯一解决方法是删除第一次出现的 @OneToOne 和 class "One" 中的字段 "two" 但是 One 的实例包含的 Two 的实例没有当我删除 One 的这个实例时 longer 被删除,这就是我使用 CascadeType.ALL.
的原因此 JPA 源代码由 Netbeans 8 自动生成。我有点不知所措。有没有办法让它正常工作?这真的是 Hibernate 的限制吗?是否有另一种 JPA 实现可以正确处理这种情况?
我认为问题出在您的 @JoinColumn
映射中使用的 name
属性,在您的 Two
class 中,其中用于 name
与 referencedColumnName
.
事实上 Two
class 已经从其 TwoPk
class 中嵌入了 P_ID
和 L_ID
属性,因此当您使用相同的名称 name = "P_ID"
和 name = "L_ID"
,你不能映射两个 class 因为这些属性已经在这个 Entity
中所以你应该指定不同的名称:
@JoinColumns({
@JoinColumn(name = "OneP_ID", referencedColumnName = "P_ID", insertable = false, updatable = false),
@JoinColumn(name = "OneL_ID", referencedColumnName = "L_ID", insertable = false, updatable = false)})
@OneToOne(optional = false)
private One one;
注:
如果您对 PK 使用两个不同的 classes,为什么在两个 classes 中使用相同的属性名称,最好在 [=] 中使用不同的名称来标识它们23=] 和 TwoPk
为:
分别oneDId
和oneLId
在你的OnePk
class和twoDId
和twoLId
在你的TwoPk
class, 这将使事情变得更好,更容易阅读、识别和映射。
起初,我通过调用 this method 增加了 Oracle UCP 中的 TTL 连接超时,以摆脱 GenericJDBCException
。某些请求的执行时间太长,而允许保持连接使用的时间太短。
其次,我使用相同的 class 命名为 OnePK 作为 classes One 和 Two 的主键。
第三,我将@XmlTransient
添加到方法getOne()之前的两个class中,以修复XML序列化中的循环。
第四,我修改了我的管理器,以便他们调用 Two.setOne(final One one) 以便在不使用 Web 服务的情况下为调用持久层的源代码公开完整的对象(Two 的实例)。
最后,我通过 @MapsId
.