简体   繁体   English

为什么@ManyToMany无法与非主键列一起使用?

[英]Why is @ManyToMany not working with non-primary key columns?

I have 2 entities - User and Role which have following relations: User has a manytomany relation to itself and a manytomany relation with the Role entity. 我有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;

...
}

and Role: 和作用:

public class RoleEntity implements Serializable{

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

    ...
}

The strange thing about the setup of DB is that the User_User relation is based on the binary Id keys 关于数据库设置的奇怪之处在于,User_User关系基于二进制Id键

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

and the user-role is based on varchars 并且用户角色基于varchars

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

Now, when it runs, the user-user relationship work well. 现在,当它运行时,用户-用户关系可以很好地工作。 However, when I try to access the collection returned for roles, I get a ClassCastException: 但是,当我尝试访问为角色返回的集合时,出现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)

It looks like the UserEntity is being cast to some binary(?) thing. 看起来UserEntity正在转换为某些binary(?)事物。 However, the first relation between users themselves works fine, but the one with another table is wrong. 但是,用户自身之间的第一个关系很好,但是与另一个表的关系是错误的。

I am using different columns of different types to join tables. 我正在使用不同类型的不同列来联接表。 Is it allowed to do it this way? 可以这样做吗?

Another strange thing is that when I switch the @Id annotation to be on the login field, the roles work fine, no issue, but then of course the self-join PersistentBag key is the Login instead of Id, which breaks the relation and no results are retrieved. 另一个奇怪的事情是,当我将@Id注释切换为登录字段时,角色可以正常工作,没有问题,但是,当然,自联接PersistentBag键是Login而不是Id,这破坏了关系并且没有结果被检索。 But the conversion from UserEntity to the "[B" is not done. 但是没有完成从UserEntity到“ [B”的转换。

Also if I leave things as in example and change the Id type to String (and the DB to varchar) it also starts working (of course not consistently with the User_User table). 另外,如果我将示例中的内容保留下来,并将Id类型更改为String(将DB更改为varchar),它也将开始工作(当然与User_User表不一致)。

What am I doing wrong? 我究竟做错了什么? What is the reason for getting the classcastexception in this case? 在这种情况下获得classcastexception的原因是什么? Why it work when I change the byte[] to String? 当我将byte []更改为String时,为什么它可以工作? Please let me know if you have any ideas. 如果您有任何想法请告诉我。 I do not want to change the DB design cause this would lead to lots migration and compatibility issues for clients already using the DB. 我不想更改数据库设计,因为这会给已经在使用数据库的客户端带来很多迁移和兼容性问题。

Just a note: the @Id has to be on the Id binary field as otherwise I wouldn't be able to make a self-join (I was unable to point twice to a column not being a primary key see: Is Hibernate ManyToMany self-join possible for non-key columns? getting mappingException ). 请注意:@Id必须在Id二进制字段上,否则我将无法进行自我联接(我无法两次指向不是主键的列,请参见: Hibernate ManyToMany self -非键列是否可能加入?获得mappingException )。

Cheers Adam 干杯亚当

the referred column in your join table must be unique entry, here if you put @Id on login field then it works fine,but when you change it to different other than @Id column you cant be sure about the entries will be unique.what you can do is, 联接表中的被引用列必须是唯一条目,在这里,如果您将@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; 

I think it should work. 我认为应该可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM