2014-08-28 123 views
1

我试图使用JPA来坚持用户对象并出现问题。用户引用一组角色对象,它是一个抽象类,它有多个子类。目前,我只有一个 - 管理员。JPA:坚持引用抽象类集合的对象

下面是用户等级:

@Entity(name = "USERS") 
public class User implements Serializable{ 

    @Id 
    @Column(name = "USERNAME") 
    private String username; 

    @Column(name = "PASSWORD") 
    private String password; 

    @Column(name = "FIRST_NAME") 
    private String firstName; 

    @Column(name = "LAST_NAME") 
    private String lastName; 

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    @JoinColumn(name = "ROLE_ID") 
    private Set<Role> roles; 

    public User(){ 
     roles = new HashSet<Role>(); 
    } 

    public String getUsername() { 
     return username; 
    } 
    public void setUsername(String username) { 
     this.username = username; 
    } 
    public String getPassword() { 
     return password; 
    } 
    public void setPassword(String password) { 
     this.password = password; 
    } 
    public String getFirstName() { 
     return firstName; 
    } 
    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 
    public String getLastName() { 
     return lastName; 
    } 
    public void setLastName(String lastName) { 
     this.lastName = lastName; 
    } 

    public Set<Role> getRoles(){ 
     return roles; 
    } 

    public void setRoles(Set<Role> roles){ 
     this.roles = roles; 
    } 

    public void addRole(Role role){ 
     roles.add(role); 
    } 
} 

这里是角色:

@Entity(name = "ROLES") 
@Inheritance(strategy=InheritanceType.JOINED) 
public abstract class Role implements Serializable{ 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name = "ROLE_ID") 
    int id; 


    public void setId(int id){ 
     this.id = id; 
    } 

    public int getId(){ 
     return id; 
    } 
} 

这里是联系(空的现在,但稍后将添加的东西出来)。

@Entity(name = "ADMINS") 
public class Admin extends Role{ 

} 

现在这里是代码,我创建的对象,并试图坚持他们。我想能够坚持一个用户对象,并让它的角色对象自动保持 - 我相信在用户中的CascaseType.ALL这样做。

public class JPAManager { 

    public void persist(Serializable s){ 
     EntityManagerFactory emf = getEntityManagerFactory(); 
     EntityManager em = emf.createEntityManager(); 
     EntityTransaction et = em.getTransaction(); 

     et.begin(); 
     em.persist(s); 
     et.commit(); 
     em.close(); 
     emf.close(); 
    } 


    protected EntityManagerFactory getEntityManagerFactory(){ 
     return Persistence.createEntityManagerFactory("main"); 
    } 

} 

最后,这里是主要的方法:

public static void main(String[] args) { 
     ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");  

     User user = new User(); 
     user.setUsername("Chris842"); 
     user.setPassword("123456"); 
     user.setFirstName("Chris"); 
     user.setLastName("Jones");  
     user.addRole(new Admin()); 

     UserDAO dao = context.getBean("userDAO", UserDAO.class); 
     dao.persist(user); 
     System.out.println("Done"); 
    } 

编辑:第一个答案之后,我尝试这样做的主要方法,但得到了同样的异常:

 Admin admin = new Admin(); 
     admin.setId(1); 
     user.addRole(admin); 

当运行上面的过程,我的数据库中创建了两个名为USERS,ROLES和ADMINS的表。用户和角色/ ADMINS之间似乎没有联系。我期望在USERS中有一个ROLE_ID(或者在ROLES中有一个USERNAME),但是两者都没有。

这是堆栈跟踪。谢谢你的帮助。我很感激它,一直试图弄清楚这个问题已有好多年了!

Hibernate: 
    select 
     hibernate_sequence.nextval 
    from 
     dual 
Hibernate: 
    insert 
    into 
     USERS 
     (PASSWORD, FIRST_NAME, LAST_NAME, USERNAME) 
    values 
     (?, ?, ?, ?) 
Hibernate: 
    insert 
    into 
     ROLES 
     (ROLE_ID) 
    values 
     (?) 
Hibernate: 
    insert 
    into 
     ADMINS 
     (ROLE_ID) 
    values 
     (?) 
Hibernate: 
    update 
     ROLES 
    set 
     ROLE_ID=? 
    where 
     ROLE_ID=? 
Exception in thread "main" javax.persistence.RollbackException: Error while commiting the transaction 
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:71) 
    at com.fdm.tradingplatform.dao.JPAManager.persist(JPAManager.java:21) 
    at com.fdm.tradingplatform.dao.UserDAO.persist(UserDAO.java:21) 
    at Main.main(Main.java:28) 
Caused by: org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:249) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:143) 
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000) 
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338) 
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106) 
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54) 
    ... 3 more 
Caused by: java.sql.BatchUpdateException: ORA-01722: invalid number 

    at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343) 
    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10768) 
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723) 
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242) 
    ... 11 more 

回答

1

没有与此属性的问题:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
@JoinColumn(name = "ROLE_ID") 
private Set<Role> roles; 

您正在尝试使用一个角色的ID作为外键的用户。相反,Role应具有User属性,并且您应该使用此属性映射用户类中的角色。

Role类添加user

@Entity(name = "ROLES") 
@Inheritance(strategy=InheritanceType.JOINED) 
public abstract class Role implements Serializable{ 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    @Column(name = "ROLE_ID") 
    int id; 

    @ManyToOne 
    @JoinColumn(name = "USER_ID") 
    User user; 

    ... 
} 

而在User类,角色集改成这样:

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
private Set<Role> roles; 
+0

在阅读本文之后5分钟内解决问题,花费时间后!谢谢! :) 我只需要稍微改变Role中的User属性。我对它的注释是(在)ManyToOne和(在)JoinColumn(name =“USER_ID”)。 (at)Column本身在User上导致了User类中mappedBy属性上的编译错误。 – Chris 2014-08-29 09:32:22

+0

无法将@符号放在上面的评论中 - 所以我以为我试图给用户加标签。 – Chris 2014-08-29 09:32:45

+0

@Chris你说得对,我编辑了我的答案。 – WilQu 2014-08-29 09:35:48

0

我认为问题在于你正在制作一个新的Admin(),但没有保留它。您需要坚持它,以便它有一个ID,以便您可以将其添加到用户。否则,你要向int/long id字段添加一个空ID,并且抛出该异常。

+0

制作一个新的管理员(),但不坚持吧.. 。当我坚持用户时,我认为我坚持了它,因为所有的策略都是级联的? 我试着改变主要方法到上面(编辑问题),我得到相同的例外。如果可以,我宁愿不要这样做,因为我想让它自动生成一个ID。也试着改变persist()来合并()和再次,同样的例外。我认为merge()更好,因为有时候我会坚持一个用户角色已经存在。 – Chris 2014-08-29 08:58:36

+0

我刚刚阅读了关于@GeneratedValue AUTO和IDENTITY在调用commit()时会生成一个值,但是当调用persist()时SEQUENCE会生成一个值,所以我可能想要使用它并对其进行了更改。尽管如此,仍然得到例外。 – Chris 2014-08-29 09:11:46

+0

我说你需要有管理员管理员=新的管理(); dao.persist(管理员); user.addRole(管理员);您仍在添加数据库中不存在的内容。 – djb 2014-08-29 09:18:57