java - 如何使用包含生成值的复合主键创建实体

标签 java hibernate jpa primary-key composite

使用 Hibernate + 注释,我正在尝试执行以下操作:

两个实体,Entity1 和 Entity2。

  • Entity1 包含一个简单的生成值主键。
  • Entity2主键由一个简单的生成值+实体一的id组成(多对一关系)

不幸的是,我做不到。

这是代码的摘录:

@Entity
public class Entity1 {

 @Id @GeneratedValue
 private Long id;

 private String name;

    ...
}

@Entity
public class Entity2 {

 @EmbeddedId
 private Entity2PK pk = new Entity2PK();

 private String miscData;

    ...
}

@Embeddable
public class Entity2PK implements Serializable {

 @GeneratedValue
 private Long id;

 @ManyToOne
 private Entity1 entity;
}

void test() {

    Entity1 e1 = new Entity1();
    e1.setName("nameE1");
    Entity2 e2 = new Entity2();

    e2.setEntity1(e1);
    e2.setMiscData("test");

    Transaction transaction = session.getTransaction();
    try {
     transaction.begin();

     session.save(e1);
     session.save(e2);

     transaction.commit();
    } catch (Exception e) {
     transaction.rollback();
    } finally {
     session.close();
    }
}

当我运行测试方法时,出现以下错误:

Hibernate: insert into Entity1 (id, name) values (null, ?)
Hibernate: call identity()
Hibernate: insert into Entity2 (miscData, entity_id, id) values (?, ?, ?)
07-Jun-2010 10:51:11 org.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 0, SQLState: null
07-Jun-2010 10:51:11 org.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: failed batch
07-Jun-2010 10:51:11 org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SEVERE: Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
 at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
 at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
 at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
 at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:254)
 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
 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:1001)
 at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:339)
 at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
 at test.App.main(App.java:32)
Caused by: java.sql.BatchUpdateException: failed batch
 at org.hsqldb.jdbc.jdbcStatement.executeBatch(Unknown Source)
 at org.hsqldb.jdbc.jdbcPreparedStatement.executeBatch(Unknown Source)
 at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
 at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:247)
 ... 8 more

请注意,我使用的是 HSQLDB。

有什么问题吗?

最佳答案

如果您想要这种行为,请执行以下操作(您需要使用属性访问而不是字段一)

Parent.class(注意类型 MutableInt 和 addChild 的属性作为设置双方的方式)

@Entity
public class Parent implements Serializable {

    private MutableInt id = new MutableInt();

    private List<Child> childList = new ArrayList();

    @OneToMany(mappedBy="parent")
    @JoinColumn(name="PARENT_ID", insertable=false, updatable=false)
    @Cascade(CascadeType.SAVE_UPDATE)
    public List<Child> getChildList() {
        return childList;
    }

    public void setChildList(List<Child> childList) {
        this.childList = childList;
    }

    @Id
    @GeneratedValue
    public Integer getId() {
        return id.intValue();
    }

    public void setId(Integer id) {
        this.id.setValue(id);
    }

    @Transient
    public MutableInt getIdAsMutableInt() {
        return id;
    }

    /**
     * Add convenience method 
     * 
     * A way to set up both sides (You have a bi-directional relationship, right ???)
     */
    public void addChild(Child child) {
        if(child.getChildId() == null)
            child.setChildId(new Child.ChildId());

        child.getChildId().setParentIdAsMutableInt(id);

        getChildList().add(child);

        child.setParent(this);
    }

}

Child.class(注意静态内部类)

@Entity
public class Child implements Serializable {

    private ChildId childId;

    private Parent parent;

    @EmbeddedId
    public ChildId getChildId() {
        return childId;
    }

    public void setChildId(ChildId childId) {
        this.childId = childId;
    }

    @ManyToOne
    @JoinColumn(name="PARENT_ID", insertable=false, updatable=false)
    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }

    /**
      * Composite primary key class MUST override equals and hashCode
      */
    @Embeddable
    public static class ChildId implements Serializable {

        private MutableInt parentId = new MutableInt();

        private Integer chId;

        public void setParentIdAsMutableInt(MutableInt parentId) {
            this.parentId = parentId;
        }

        @GeneratedValue
        public Integer getChId() {
            return chId;
        }

        public void setChId(Integer chId) {
            this.chId = chId;
        }

        @Column(name="PARENT_ID")
        public Integer getParentId() {
            return parentId.intValue();
        }

        public void setParentId(Integer parentId) {
            this.parentId.setValue(parentId);
        }

        @Override
        public boolean equals(Object o) {
            if(!(o instanceof ChildId))
                return false;

            final ChildId other = (ChildId) o;
            return new EqualsBuilder()
                       .append(getChId(), other.getChId())
                       .append(getParentId(), other.getParentId()).isEquals();
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 11 * hash + getParentId().hashCode();
            hash = 11 * hash + getChId().hashCode();
            return hash;
        }

    }

}

并进行测试

Session session = configuration.buildSessionFactory().openSession();
session.beginTransaction();

Parent parent = new Parent();
parent.addChild(new Child());

session.save(parent);

session.getTransaction().commit();

你需要一个 MutableInt 因为 Integer 是不可变的实例。但是您的 MutableInt 字段由 Integer 属性封装。仔细看

关于java - 如何使用包含生成值的复合主键创建实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2988173/

相关文章:

java - 在 Hibernate 中将实体字段子集映射为单独的类的有效方法

hibernate - Seam POJO 的手动事务

java - JPA CriteriaBuilder - 按一对多关系中关联实体的数量排序

java - ZXing 库无法解码 Datamatrix 条码

java - 在 Spring MVC 中,使用 HQL JOIN 我多次获得相同的数据

java - Hibernate实体虚拟列错误?

java - 从 java -jar 运行 spring boot 应用程序时未提交事务

java - Java 冰雹程序

java - 如何在 Flex/BlazeDS 中同时支持 HTTP 和 HTTPS channel ?

Java 上下文 sax/stax 解析