为什么@ManyToMany不能使用非主键列?

时间:2014-09-05 15:28:56

标签: java hibernate jpa many-to-many classcastexception

我有2个实体 - 用户和角色有以下关系:用户与自身有很多关系,与角色实体有很多关系。

@Entity
public class UserEntity implements Serializable {

    @Id
    @Column(length = 12, columnDefinition = "BINARY(12)", name = "Id", unique = true)
    private byte[] id;

    @Column(name = "Login", unique = true, nullable = false)
    private String login;

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "User_Role",
    joinColumns = { @JoinColumn(name = "UserLogin", referencedColumnName = "Login") },
    inverseJoinColumns = { @JoinColumn(name = "RoleId", referencedColumnName = "Id") })
    private Set<RoleEntity> roles;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "User_User",
    joinColumns = { @JoinColumn(name = "UserParent") },
    inverseJoinColumns = { @JoinColumn(name = "UserChild") })
    private Collection<UserEntity> children;

...
}

和角色:

public class RoleEntity implements Serializable{

    @Id
    @Column(name = "Id", unique = true, nullable = false)
    private String id;

    ...
}

关于DB设置的奇怪之处在于User_User关系基于二进制Id键

create table if not exists User_User (
    UserParent binary,
    UserChild binary
);

,用户角色基于varchars

create table if not exists KNUser_UserRole (
    UserLogin varchar, 
    RoleId varchar,
);

现在,当它运行时,用户 - 用户关系运行良好。但是,当我尝试访问为角色返回的集合时,我得到一个ClassCastException:

java.lang.ClassCastException: **.entity.UserEntity cannot be cast to [B
    at org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor.extractHashCode(PrimitiveByteArrayTypeDescriptor.java:41)
    at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:201)
    at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:205)
    at org.hibernate.engine.spi.EntityKey.generateHashCode(EntityKey.java:114)
    at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:79)
    at org.hibernate.internal.AbstractSessionImpl.generateEntityKey(AbstractSessionImpl.java:240)
    at org.hibernate.engine.internal.StatefulPersistenceContext.getCollectionOwner(StatefulPersistenceContext.java:740)
    at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1181)
    at org.hibernate.loader.Loader.readCollectionElements(Loader.java:800)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:651)
    at org.hibernate.loader.Loader.doQuery(Loader.java:856)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
    at org.hibernate.loader.Loader.loadCollection(Loader.java:2175)
    at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:61)
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:622)
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:82)
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1606)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:379)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:112)
    at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)

看起来UserEntity被强制转换为某些二进制(?)的东西。但是,用户之间的第一个关系本身可以正常工作,但是另一个表之间的关系是错误的。

我使用不同类型的不同列来连接表。允许这样做吗?

另一个奇怪的事情是,当我将@Id注释切换到 登录 字段时,角色工作正常,没有问题,但当然是自我-join PersistentBag键是Login而不是Id,它会破坏关系并且不会检索任何结果。但是从UserEntity到“[B”的转换没有完成。

此外,如果我将示例中的内容更改为String(并将DB更改为varchar),它也会开始工作(当然不能与User_User表一致)。

我做错了什么?在这种情况下获取classcastexception的原因是什么?当我将byte []更改为String时,为什么它可以工作?如果您有任何想法,请告诉我。我不想更改数据库设计,因为这会导致已经使用数据库的客户端出现大量迁移和兼容性问题。

只是注意:@Id必须在Id二进制字段上,否则我将无法进行自联接(我无法指向两次不是主键的列,请参阅:{ {3}})。

干杯 亚当

1 个答案:

答案 0 :(得分:0)

连接表中的引用列必须是唯一条目,如果你在登录字段上放置@Id然后它工作正常,但当你将它改为@Id列以外的其他时你不能确定条目将是unique.what你能做的是,

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "User_Role",
joinColumns = { @JoinColumn(name = "UserLogin", referencedColumnName = "Id") },
inverseJoinColumns = { @JoinColumn(name = "RoleId", referencedColumnName = "Id") })
private Set<RoleEntity> roles; 

我认为它应该有效。