小编典典

如何创建支持通用ID(包括自动生成的ID)的通用实体模型类?

hibernate

我有三个 种类的 对表的主键:

  • INT自动生成的主键,使用AUTO_INCREMENT数据库供应商(MySQL)的容量
  • CHAR(X) 主键,用于将用户可读的值存储为键(其中X是数字,并且50 <= X <= 60)
  • 复杂的主键,由表的2或3个字段组成。

另外,可能存在(或不存在)一些字段:

  • 版本,INT字段。
  • createdBy VARCHAR(60)字段和lastUpdatedBy VARCHAR(60)字段(还有更多字段,但这些涵盖了基本示例)。

以上示例:

  • 表格1
    • id int主键auto_increment
    • 版本int
    • 值char(10)
    • 由varchar(60)创建
    • lastUpdatedBy varchar(60)
  • 表2
    • id char(60)主键
    • shortDescription varchar(20)
    • longDescription varchar(100)
  • 表3
    • field1 int主键
    • field2 int主键
    • 十进制数(10,5)
    • 版本int

考虑到所有这些,我需要创建一组通用类来支持这些要求,并允许使用Hibernate 4.3和JPA 2.1进行CRUD操作。

这是我当前的模型(避免使用getter / setter来缩短代码示例):

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    protected T id;
}

@MappedSuperclass
public abstract class VersionedEntity<T> extends BaseEntity<T> {
    @Version
    protected int version;
}

@MappedSuperclass
public abstract class MaintainedEntity<T> extends VersionedEntity<T> {
    @Column
    protected String createdBy;
    @Column
    protected String lastUpdatedBy;
}

@Entity
public class Table1 extends MaintainedEntity<Long> {
    @Column
    private String value;
}

@Entity
public class Table2 extends BaseEntity<String> {
    @Column
    private String shortDescription;
    @Column
    private String longDescription;
}

我目前正在测试保存的实例Table1Table2。我有以下代码:

SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.getCurrentSession();
session.beginTransaction();

Table1 newTable1 = new Table1();
newTable1.setValue("foo");
session.save(newTable1); //works

Table2 newTable2 = new Table2();
//here I want to set the ID manually
newTable2.setId("foo_id");
newTable2.setShortDescription("short desc");
newTable2.setLongDescription("long description");
session.save(newTable2); //fails

session.getTransaction().commit();
sf.close();

尝试保存时失败,Table2并且出现以下错误:

Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:996)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)

该错误消息很明显,因为CHAR(X)字段没有默认值,并且也没有默认值(AFAIK)。我尝试将生成策略更改为,GenerationType.AUTO并得到了相同的错误消息。

我如何重塑这些类以支持这些要求?甚至更好的是,我如何提供一种取决于我所保存实体的密钥的生成策略,该策略可以由我自动生成或提供?

涉及的技术:

  • Java SDK 8
  • hibernate4.3.6
  • JPA 2.1
  • MySQL和Postgres数据库
  • 操作系统:Windows 7 Professional

注意:为了可以得到JPA 2.1的其他实现(如EclipseLink)的支持,以上内容可能会(可能会)更改。


阅读 388

收藏
2020-06-20

共1个答案

小编典典

您可以“强制解决”此强制派生类以实现方法,该方法将确保分配ID并使用@PrePersist对该方法进行注释。您可以为将为其自动生成ID的类提供默认实现。

Somethig喜欢:

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    protected T id;

    @PrePersist
    public void ensureIdAssigned() {
          ensureIdAssignedInternal();  
    }


    public abstract void ensureIdAssignedInternal();  
}


@MappedSuperclass
public abstract class AutoIdMaintaintedEntity<T> extends MaintainedEntity<T> { // provide default implementation for Entities with Id generated by @GeneratedValue(strategy=GenerationType.IDENTITY) on BaseEntity superclass
    public void ensureIdAssignedInternal() {
        // nothing here since the Id will be automatically assigned
    }
}

@Entity
public class Table1 extends AutoIdMaintaintedEntity<Long> {
    @Column
    private String value;
}

@Entity
public class Table2 extends BaseEntity<String> {
    @Column
    private String shortDescription;
    @Column
    private String longDescription;

    public void ensureIdAssignedInternal() {
         this.id = generateMyTextId();

    }

     private String generateMyTextId() {
         return "text id";
     }


}
2020-06-20