【问题标题】:Why is @ManyToMany not working with non-primary key columns?为什么@ManyToMany 不能使用非主键列?
【发布时间】:2014-09-06 02:58:39
【问题描述】:

我有 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 注释切换到 login 字段时,角色工作正常,没有问题,但当然是 self -join PersistentBag 键是 Login 而不是 Id,这会破坏关系并且不会检索到任何结果。但是从 UserEntity 到“[B”的转换还没有完成。

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

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

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

干杯 亚当

【问题讨论】:

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


    【解决方案1】:

    连接表中的引用列必须是唯一条目,如果您将@Id 放在登录字段上,则它可以正常工作,但是当您将其更改为除@Id 列之外的其他列时,您无法确定条目将是独一无二。你能做的是,

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

    我认为它应该有效。

    【讨论】:

    • 不,正如我写的那样,UserLogin referencedColumnName 必须是 Login - Id 是二进制的,而 Login 是 varchar。对于这种关系,我需要一个 varchar。我知道这是一个糟糕的设计,但我正在寻找解决方案。
    猜你喜欢
    • 2012-01-05
    • 2023-02-25
    • 1970-01-01
    • 2011-04-23
    • 2019-02-08
    • 1970-01-01
    • 2021-10-10
    • 2011-02-07
    • 2014-02-05
    相关资源
    最近更新 更多