JPA:持久化一个引用抽象类集合的Object

时间:2014-08-28 15:01:29

标签: java hibernate jpa

我正在尝试使用JPA来持久化User对象并遇到问题。 User引用一组Role对象,它是一个抽象类,它将具有多个子类。目前,我只有一个 - 管理员。

这是User类:

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

这是Admin(现在是空的,但稍后会添加内容)。

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

}

现在这里是我正在创建对象并试图保留它们的代码。我希望能够持久保存User对象并让它的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");
    }

编辑:在第一个答案之后,我在main方法中尝试了这个但得到了同样的例外:

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

运行上述内容时,我的数据库中会创建两个名为USERS,ROLES和ADMINS的表。 USERS和ROLES / 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

2 个答案:

答案 0 :(得分:1)

此属性存在问题:

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

您尝试将角色的ID用作用户的外键。相反,Role应该具有User属性,您应该使用此属性来映射用户类中的角色。

user课程中添加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;

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

    ...
}

User类中,将角色集更改为:

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

答案 1 :(得分:0)

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