代码之家  ›  专栏  ›  技术社区  ›  psychollek

JPA 2 Hibernate映射,在主键中使用带有三层结构的@IdClass

  •  4
  • psychollek  · 技术社区  · 10 年前

    这个问题非常类似于: JPA (Hibernate, EclipseLink) mapping: why doesn't this code work (chain of 2 relationships using JPA 2.0, @EmbeddedId composite PK-FK)?

    实际上,我唯一(从我发现的有意义的地方)的区别是我使用 @IdClass 而且我很可能无法切换到与hibernate不同的提供商。

    但无论如何,这里是代码(删除了不重要的部分):

    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 :

    @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 :

    @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 ...
       }
    }
    

    我得到的是:

     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
    

    是否有人知道这是一个休眠错误,我应该将其发布在他们的问题跟踪系统上(并祈祷我能够更新到给定的休眠版本),或者我绑定实体的方式有什么根本错误?

    我已经在EAP6.1(4.2.0)和wildfly(不知道是哪一个)上用hibernate实现检查了它

    2 回复  |  直到 7 年前
        1
  •  2
  •   psychollek    10 年前

    好的,这就是我目前所发现的:

    谢谢我的朋友: https://hibernate.atlassian.net/browse/HHH-5764 这很可能是这种行为的原因。

    我找到了一个解决方法:

    许可.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 ...
       }
    }
    

    这种解决方法的好处是它不会以任何方式更改类的公共API (唯一的变化是,我需要使PermissionPk可以看到上下文和上下文类型Pk中的字段-它们以前是私有的,只有一个公共构造函数(但再次简化了这个问题)),也没有改变jpql查询,同时,解决方法是可扩展的(可以扩展到任何级别-只要每个偶数Pk都不包含另一个Pk),因此,如果这个bug能够得到解决,那么很容易删除解决方法。

    我仍然很乐意接受对我的解决方法或问题本身的任何评论。

        2
  •  0
  •   psychollek    10 年前

    今天我找到了另一个解决方法:) 您可以完全省略@IdClass,并使用特定于休眠的功能来动态创建复合键,因为它显然不受此错误的影响。 这里的缺点是:

    1. 它完全是Hibernate特有的,JPA根本没有涉及。
    2. 无法执行em.find(ClassName.class,newClassPk(args…)),因为根本没有ClassPk。

    但是,如果你可以使用除休眠之外的任何东西,那么你也可以使用没有这个bug的东西——所以1可能真的不是问题。还有一种可能性是,您实际上不需要这个实体的em.find(或者可以通过会话或jpql查询来创建它)。