JPA @ManyToOne连接表问题

时间:2016-08-20 02:38:31

标签: java mysql jpa glassfish eclipselink

我正在开发一种适合GlassFish JDBC Realm要求的身份验证模型。

在这个模型中,我有一个可以包含多个用户的组,但每个用户只能在一个组中(例如su,admin等)。

我有两个实体:Groups.java(用于组)和Credential.java(用于用户),并打算将生成的连接表提供给Glassfish" Group Table"属性。

我能够持久保存Groups和Credential实例,但是甚至没有创建所需的中间表(credential_groups),更不用说更新了。

以下是我的实体:

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:

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

正如我所说,坚持两个工作(对于我也尝试更新,查询的组),但是这个错误会继续在任何一个实体的每个操作上触发:

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)")

重要更新: 这是在粘贴的上述异常之前抛出的错误:

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))

根据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));
    }

我的代码基于Manning的EJB 3.0 in Action中的指令,并尝试根据此stackoverflow答案解决连接表问题:How to create join table with JPA annotations?

有人可以帮我创建和更新联接表吗?非常感谢你。

1 个答案:

答案 0 :(得分:0)

通过添加{{来修复所拥有实体的mappedBy注释中的@OneToMany属性(这修复了非创建连接表) 1}}属性(设置为true - 这解决了“unique”问题)到同一属性的PRIMARY KEY (credential, group)内的@JoinColumn注释:

@JoinTable

Main Take away永远不会在ManyToOne / OneToMany实体对中将“mappedBy”与@OneToMany @JoinTable( name = "credential_groups", joinColumns = @JoinColumn(name = "group_name"), inverseJoinColumns = @JoinColumn(name = "username", unique=true) ) public Set<Credential> getCredentials() { return credentials; } 组合。

相关问题