[英]JPA 2 Hibernate mapping with composite key in primary key using @IdClass with 3 tier structure
This question is very similar to: JPA (Hibernate, EclipseLink) mapping: why doesn't this code work (chain of 2 relationships using JPA 2.0, @EmbeddedId composite PK-FK)? 这个问题非常类似于: JPA(Hibernate,EclipseLink)映射:为什么这段代码不起作用(使用JPA 2.0,@ EmbeddedId复合PK-FK的2个关系链)?
Actually my only (from meaningful that I spotted) difference is that I use @IdClass
and that I most probably won't be able to switch to a different provider than hibernate. 实际上我的唯一(从我发现的有意义的)差异是我使用
@IdClass
并且我很可能无法切换到与hibernate不同的提供者。
but anyway here is the code (removed parts that where unimportant): 但无论如何这里是代码(删除不重要的部分):
PermissionContextType.java
: PermissionContextType.java
:
@Entity
@IdClass(PermissionContextTypePk.class)
public class PermissionContextType{
@Id
private String id;
@Id
@JoinColumn (name = "PROJECT", referencedColumnName = "ID")
@ManyToOne ()
private Project project;
public static class PermissionContextTypePk implements Serializable{
public String project;
public String id;
// ... eq and hashCode here ...
}
}
PermissionContext.java
: PermissionContext.java
:
@Entity
@IdClass(PermissionContextPk.class)
public class PermissionContext{
@Id
private String id;
@Id
@JoinColumns ({
@JoinColumn (name = "PROJECT", referencedColumnName = "PROJECT"),
@JoinColumn (name = "PERMISSIONCONTEXTTYPE", referencedColumnName = "ID")
})
@ManyToOne
private PermissionContextType permissionContextType;
public static class PermissionContextPk implements Serializable{
public String id;
public PermissionContextTypePk permissionContextType;
// ... eq and hashCode here ...
}
}
Permission.java
: Permission.java
:
@Entity
@IdClass(PermissionPk.class)
public class Permission{
@Id
private String id;
@Id
@JoinColumns ({
@JoinColumn (name = "PROJECT", referencedColumnName = "PROJECT"),
@JoinColumn (name = "PERMISSIONCONTEXTTYPE", referencedColumnName = "PERMISSIONCONTEXTTYPE"),
@JoinColumn (name = "PERMISSIONCONTEXT", referencedColumnName = "ID")
})
@ManyToOne
private PermissionContext permissionContext;
public static class PermissionPk implements Serializable{
public String id;
public PermissionContextPk permissionContext;
// ... eq and hashCode here ...
}
}
and what I get is: 而我得到的是:
org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: PermissionContext
Caused by: org.hibernate.AssertionFailure: org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: PermissionContext
does anybody know if this is a hibernate bug and I should post it on their issue tracking system (and pray that I would be able to update to given hibernate version) or is there something fundamentally wrong with my way of binding the entities? 有没有人知道这是一个hibernate错误,我应该将它发布在他们的问题跟踪系统上(并祈祷我能够更新到给定的hibernate版本)或者我的绑定实体的方式是否存在根本错误?
I've checked it with the hibernate implementation on EAP 6.1 (4.2.0) as well as on wildfly (don't really know which one.) 我已经使用EAP 6.1(4.2.0)上的hibernate实现以及wildfly(不知道哪一个)进行了检查。
Ok, so this is what I found so far : 好的,所以这是我到目前为止所发现的:
Thanks fr my friend : https://hibernate.atlassian.net/browse/HHH-5764 which most probably is the reason for this behaviour. 谢谢我的朋友: https : //hibernate.atlassian.net/browse/HHH-5764这很可能就是这种行为的原因。
And I found a workaround : 我发现了一个解决方法:
Permission.java: Permission.java:
@Entity
@IdClass(PermissionPk.class)
public class Permission{
@Id
private String id;
// for the next 3 fields there are no public acessors, so the public API of the class was not changed !
@Id
@Column(name = "PROJECT")
private String projectId;
@Id
@Column(name = "PERMISSIONCONTEXTTYPE")
private String permissionContextTypeId;
@Id
@Column(name = "PERMISSIONCONTEXT")
private String permissionContextId;
@JoinColumns ({
@JoinColumn (name = "PROJECT", referencedColumnName = "PROJECT", updatable = false, insertable = false),
@JoinColumn (name = "PERMISSIONCONTEXTTYPE", referencedColumnName = "PERMISSIONCONTEXTTYPE", updatable = false, insertable = false),
@JoinColumn (name = "PERMISSIONCONTEXT", referencedColumnName = "ID", updatable = false, insertable = false)
})
@ManyToOne
private PermissionContext permissionContext;
public static class PermissionPk implements Serializable{
// previously they where private as well, but removed public constructor for the sake of simplicity of the question - so no changes where necesary in public API of the class !
private String id;
private String projectId;
private String permissionContextTypeId;
private String permissionContextId;
public PermissionPk () {}
public PermissionPk (String aId, PermissionContextPk aPermissionContext) {
this.id = aId;
permissionContextId = aPermissionContext.id;
permissionContextTypeId = aPermissionContext.permissionContextType.id;
projectId = aPermissionContext.permissionContextType.project;
}
... eq and hashCode here ...
}
}
The good thing about this workaround is that it does not change the public API of the class in any way (the only change was that I needed to make fields in Pk's of context and contexttype visible to the PermissionPk - they where private before with only a public constructor [but again simplified for the question]), nor did it change the jpql queries, and at the same time workaround is scalable (to any tier amount - as long as every even pk does not contain another pk), so if the bug will be resolved it will be easy to remove the workaround. 这个解决方法的好处是它不会以任何方式更改类的公共API(唯一的变化是我需要在Pk的上下文中创建字段,并且上下文类型对PermissionPk可见 - 它们之前是私有的,只有一个公共构造函数[但同样简化了问题]),也没有改变jpql查询,同时解决方法是可扩展的(任何层数 - 只要每个偶数pk不包含另一个pk),所以如果将解决错误,将很容易删除变通方法。
I would still gladly accept any comments on either my workaround or the question in itself. 我仍然乐意接受对我的解决方法或问题本身的任何评论。
Today I found another workaround :) You can omit @IdClass entirely and use hibernate specific ability to create composite keys on the fly as apparently it is not affected by this bug. 今天我找到了另一种解决方法:)你可以完全省略@IdClass并使用hibernate特定的能力来动态创建复合键,因为它显然不受此bug的影响。 The drawback here is that:
这里的缺点是:
But if you could use anything else than hibernate you could just as well use something without this bug - so probably 1 is not a problem really. 但是,如果你可以使用除休眠之外的任何东西,你也可以使用没有这个bug的东西 - 所以可能1真的不是问题。 and there is a possibility that you don't really need the em.find for this entity (or can live with creating it thru session or jpql query).
并且你可能不需要为这个实体提供em.find(或者可以通过session或jpql查询来创建它)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.