簡體   English   中英

如何使用包含生成值的復合主鍵創建實體

[英]How to create an entity with a composite primary key containing a generated value

使用Hibernate +批注,我正在嘗試執行以下操作:

兩個實體,Entity1和Entity2。

  • Entity1包含一個簡單的生成值主鍵。
  • Entity2主鍵由一個簡單的生成值+實體1的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。

關於什么是錯的任何想法?

請執行以下操作是否需要這種行為(需要使用屬性訪問而不是字段1)

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屬性封裝。 仔細看

您可以將嵌入式ID中的外鍵用作單獨的只讀列:

@Entity 
public class Entity2 { 

    @EmbeddedId 
    private Entity2PK pk = new Entity2PK(); 

    @ManyToOne 
    @JoinColumn(name = "entity1_id")
    private Entity1 entity; 

    ... 
} 

@Embeddable 
public class Entity2PK implements Serializable { 

    @GeneratedValue 
    private Long id; 

    @Column(name = "entity1_id", insertable = false, updateable = false)
    private Long entity1Id;

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM