简体   繁体   English

JPA @ManyToOne联接表问题

[英]JPA @ManyToOne join table issue

I am working on an authentication model that would suit GlassFish's JDBC Realm requirements. 我正在研究一种适合GlassFish的JDBC Realm要求的身份验证模型。

In this model I have one group which can contain multiple users, but each user can only be in one group (eg su, admin, etc.). 在此模型中,我有一个可以包含多个用户的组,但是每个用户只能在一个组中(例如su,admin等)。

I have two entities: Groups.java (for groups) and Credential.java (for users) and intend to feed the generated join table to Glassfish's "Group Table" property. 我有两个实体:Groups.java(对于组)和Credential.java(对于用户),打算将生成的联接表提供给Glassfish的“ Group Table”属性。

I am able to persist both Groups and Credential instances, but the required middle table (credential_groups) is not even created, let alone updated. 我可以同时保留Groups和Credential实例,但是甚至没有创建所需的中间表(credential_groups),更不用说更新了。

Below are my entities: 以下是我的实体:

Credential.java: Credential.java:

@Entity
@Access(AccessType.PROPERTY)
@Table(name = "credential")
public class Credential extends MetaInfo implements Serializable {
private String username;
private String passwd;
private Groups group;
private boolean blocked;
private boolean suspended;

public Credential() {
    super();
}

public Credential(String createdBy) {
    super(Instant.now(), createdBy);
}

public Credential(String createdBy, String username, String passwd) {
    this(createdBy);
    this.username = username;
    this.passwd = passwd;
}

@Id
@Column(name = "username")
public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
    updateModified();
}

@Column(name = "passwd")
public String getPasswd() {
    return passwd;
}

public void setPasswd(String passwd) {
    this.passwd = passwd;
    updateModified();
}

@ManyToOne(fetch = FetchType.LAZY)
public Groups getGroups() {
    return group;
}

public void setGroups(Groups group) {
    this.group = group;
    group.getCredentials().add(this);
    updateModified();
}

@Column(name = "is_blocked")
public boolean isBlocked() {
    return blocked;
}

public void setBlocked(boolean blocked) {
    this.blocked = blocked;
    updateModified();
}

@Column(name = "is_suspended")
public boolean isSuspended() {
    return suspended;
}

public void setSuspended(boolean suspended) {
    this.suspended = suspended;
    updateModified();
}
}

Groups.java: Groups.java:

@Entity
@Access(AccessType.PROPERTY)
@Table(name = "groups")
@NamedQueries({
    @NamedQuery(name = "findAllGroups",
            query = "SELECT g FROM Groups g order by g.modifiedDate DESC")
})
public class Groups extends MetaInfo implements Serializable {

private String groupName;
private Set<Credential> credentials;

public Groups() {
    super();
    credentials = new HashSet();
}

public Groups(String groupName) {
    this();
    this.groupName = groupName;
}

public Groups(String createdBy, String groupName) {
    this();
    setCreatedBy(createdBy);
    this.groupName = groupName;
}

@Id
@Column(name = "group_name")
public String getGroupName() {
    return groupName;
}

public void setGroupName(String groupName) {
    this.groupName = groupName;
    updateModified();
}

@OneToMany(mappedBy = "groups")
@JoinTable(
        name = "credential_groups",
        joinColumns = @JoinColumn(name = "group_name"),
        inverseJoinColumns = @JoinColumn(name = "username")
)
public Set<Credential> getCredentials() {
    return credentials;
}

public void setCredentials(Set<Credential> credentials) {
    this.credentials = credentials;
}

public void addCredential(Credential c) {
    credentials.add(c);
    if (c.getGroups() != this) {
        c.setGroups(this);
    }
}
}

As I said persisting both works (for Groups I have also tried updating, querying), but this error keeps on firing on every operation with either entity: 正如我所说的那样,坚持两种方法都可行(对于组,我也曾尝试过更新,查询),但是对于任何一个实体,每次操作都会触发此错误:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Can't write; duplicate key in table '#sql-4d2_54'
Error Code: 1022
Call: ALTER TABLE credential ADD CONSTRAINT FK_credential_GROUPS_group_name FOREIGN KEY (GROUPS_group_name) REFERENCES groups (group_name)
Query: DataModifyQuery(sql="ALTER TABLE credential ADD CONSTRAINT FK_credential_GROUPS_group_name FOREIGN KEY (GROUPS_group_name) REFERENCES groups (group_name)")

Important update: This is the error that is being thrown even before the pasted above exception: 重要更新:这是在粘贴以上异常之前引发的错误:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'group VARCHAR(255) NOT NULL, PRIMARY KEY (credential, group))' at line 1
Error Code: 1064
Call: CREATE TABLE credential_groups (credential VARCHAR(255) NOT NULL, group VARCHAR(255) NOT NULL, PRIMARY KEY (credential, group))

As requested by Francois Motard, here's my jUnit method that triggers the error (the group is created in another test class): 根据Francois Motard的要求,这是触发错误的jUnit方法(该组在另一个测试类中创建):

public class CredentialRepositoryTests {

private final OCGroupsRepository groupRepo;
private final OCCredentialRepository credentialRepo;

public CredentialRepositoryTests() {
    groupRepo = new OCGroupsRepository();
    credentialRepo = new OCCredentialRepository();
}
...
@Test
    public void createCredentialTest(){
        //retrieve the group
        Groups admin = groupRepo.getByGroupName("admin");
        Credential rimma = new Credential("user_creator", "sample_user", "abc123");
        admin.addCredential(rimma);
        assertTrue(groupRepo.updateGroups(admin));
    }

I based my code on the instructions from the EJB 3.0 in Action by Manning and tried to resolve the join table issue based on this stackoverflow answer: How to create join table with JPA annotations? 我的代码基于Manning在EJB 3.0中的操作说明,并试图基于以下stackoverflow答案解决联接表问题: 如何使用JPA批注创建联接表?

Can anyone help me have the join table created and updated? 谁能帮我创建和更新联接表? Thank you very much. 非常感谢你。

Resolved by removing the mappedBy attribute from the @OneToMany annotation of the owned entity (this fixed the non-creation of the join table) and by adding the unique attribute (set to true - this solved the " PRIMARY KEY (credential, group) " issue) to the @JoinColumn annotation inside the @JoinTable of the same property: 通过移除解决mappedBy从属性@OneToMany所拥有的实体的注解(这个固定的非创建连接表中)加入 unique属性(设置为true -这解决了“ PRIMARY KEY (credential, group) ”问题)的@JoinColumn内侧标注@JoinTable相同属性:

@OneToMany
@JoinTable(
        name = "credential_groups",
        joinColumns = @JoinColumn(name = "group_name"),
        inverseJoinColumns = @JoinColumn(name = "username", unique=true)
)
public Set<Credential> getCredentials() {
    return credentials;
}

Main take away don't ever ever combine a "mappedBy" with the @JoinTable in a ManyToOne/OneToMany entities pair. 主要实现永远@JoinTable在ManyToOne / OneToMany实体对中将“ mappedBy”与@JoinTable结合使用。

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

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