我正在开发一种适合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?
有人可以帮我创建和更新联接表吗?非常感谢你。
答案 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;
}
组合。