【问题标题】:JPA @EmbeddedId is not generating sequenceJPA @EmbeddedId 未生成序列
【发布时间】:2010-12-15 05:32:19
【问题描述】:

我有一个包含一个序列和两个外键的复合主键的表 我能够坚持我的实体类,但它没有按照顺序生成。具有由一个序列和两个外键组成的复合主键的表,maven中的hbm2java给出了以下实体

这里是主要实体

package aop.web.teacher.rmodels; // Generated Dec 14, 2010 8:45:32 PM by Hibernate Tools 3.2.2.GA import java.util.Date; import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; import javax.persistence.Column; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; /** * Schoolmaster generated by hbm2java */ @Entity @Table(name = "schoolmaster", schema = "public") public class Schoolmaster implements java.io.Serializable { private SchoolmasterId id; ... @EmbeddedId @AttributeOverrides({ @AttributeOverride(name = "id", column = @Column(name = "id", nullable = false)), @AttributeOverride(name = "districtId", column = @Column(name = "district_id", nullable = false)), @AttributeOverride(name = "typeOfSchool", column = @Column(name = "type_of_school", nullable = false)) }) public SchoolmasterId getId() { return this.id; } public void setId(SchoolmasterId id) { this.id = id; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "type_of_school", nullable = false, insertable = false, updatable = false) public AopTeachersTypeMaster getAopTeachersTypeMaster() { return this.aopTeachersTypeMaster; } public void setAopTeachersTypeMaster( AopTeachersTypeMaster aopTeachersTypeMaster) { this.aopTeachersTypeMaster = aopTeachersTypeMaster; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "school_nature") public AopTeachersSchoolNatureMaster getAopTeachersSchoolNatureMaster() { return this.aopTeachersSchoolNatureMaster; } public void setAopTeachersSchoolNatureMaster( AopTeachersSchoolNatureMaster aopTeachersSchoolNatureMaster) { this.aopTeachersSchoolNatureMaster = aopTeachersSchoolNatureMaster; } @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "district_id", nullable = false, insertable = false, updatable = false) public AopTeachersDistrictMaster getAopTeachersDistrictMaster() { return this.aopTeachersDistrictMaster; } public void setAopTeachersDistrictMaster( AopTeachersDistrictMaster aopTeachersDistrictMaster) { this.aopTeachersDistrictMaster = aopTeachersDistrictMaster; } @Column(name = "school_name", length = 50) public String getSchoolName() { return this.schoolName; } public void setSchoolName(String schoolName) { this.schoolName = schoolName; } @Column(name = "school_address") public String getSchoolAddress() { return this.schoolAddress; } public void setSchoolAddress(String schoolAddress) { this.schoolAddress = schoolAddress; } @Column(name = "school_phone_number", length = 12) public String getSchoolPhoneNumber() { return this.schoolPhoneNumber; } public void setSchoolPhoneNumber(String schoolPhoneNumber) { this.schoolPhoneNumber = schoolPhoneNumber; } @Temporal(TemporalType.DATE) @Column(name = "establishment_date", length = 13) public Date getEstablishmentDate() { return this.establishmentDate; } public void setEstablishmentDate(Date establishmentDate) { this.establishmentDate = establishmentDate; } @Column(name = "school_no_of_teachers") public Integer getSchoolNoOfTeachers() { return this.schoolNoOfTeachers; } public void setSchoolNoOfTeachers(Integer schoolNoOfTeachers) { this.schoolNoOfTeachers = schoolNoOfTeachers; } @Column(name = "school_no_of_students") public Integer getSchoolNoOfStudents() { return this.schoolNoOfStudents; } public void setSchoolNoOfStudents(Integer schoolNoOfStudents) { this.schoolNoOfStudents = schoolNoOfStudents; } }

这是嵌入式 PK 类。

/** * SchoolmasterId generated by hbm2java */ @Embeddable public class SchoolmasterId implements java.io.Serializable { private long id; private long districtId; private long typeOfSchool; public SchoolmasterId() { } public SchoolmasterId(long id, long districtId, long typeOfSchool) { this.id = id; this.districtId = districtId; this.typeOfSchool = typeOfSchool; } @Column(name="id", nullable=false) @GeneratedValue(strategy=GenerationType.SEQUENCE) public long getId() { return this.id; } public void setId(long id) { this.id = id; } @NaturalId @Column(name="district_id", nullable=false) public long getDistrictId() { return this.districtId; } public void setDistrictId(long districtId) { this.districtId = districtId; } @NaturalId @Column(name="type_of_school", nullable=false) public long getTypeOfSchool() { return this.typeOfSchool; } public void setTypeOfSchool(long typeOfSchool) { this.typeOfSchool = typeOfSchool; } public boolean equals(Object other) { if ( (this == other ) ) return true; if ( (other == null ) ) return false; if ( !(other instanceof SchoolmasterId) ) return false; SchoolmasterId castOther = ( SchoolmasterId ) other; return (this.getId()==castOther.getId()) && (this.getDistrictId()==castOther.getDistrictId()) && (this.getTypeOfSchool()==castOther.getTypeOfSchool()); } public int hashCode() { int result = 17; result = 37 * result + (int) this.getId(); result = 37 * result + (int) this.getDistrictId(); result = 37 * result + (int) this.getTypeOfSchool(); return result; } }

在这里,我希望 Id 是自动生成的... 我只添加了

@NaturalId

@GeneratedValue(strategy=GenerationType.SEQUENCE)

我也尝试过使用 GenerationType.AUTO 但没有用。 请提出建议。

【问题讨论】:

  • 我怀疑您没有收到答案,因为它无法完成。我有一个类似的用例(三个中的一个主键字段是自动生成的(PostgreSQL 中的 bigserial))并且发现 @GeneratedValue 只能与 @Id 结合使用。
  • 令人惊讶的是,鉴于我看到的关于它的帖子数量,它无法完成。我把它归结为 hibernate/jpa/eclipselink 开发人员的顽固,他们不想提供一些常见的用例。 “我们知道得更好”的态度之一。

标签: jpa auto-generate


【解决方案1】:

这个问题有一个解决方法。我遇到了同样的情况,有 4 个字段作为复合键,其中 1 个需要按顺序生成。 我根本没有创建嵌入式类,只有 1 个需要按序列生成的 @Id 字段。其余所有字段值将是简单列,因为在 DB 中强制执行参照完整性,并且我正在检查代码中其余 3 个字段的值是否不为空。

如果发生错误,事务将回滚。

【讨论】:

    【解决方案2】:

    只想添加我的 2c。这适用于复合主键和单个主键。防止创建序列,而是从表中选择 max + 1。

    Identifiable.java

    package my.app.hibernate;
    
    import java.io.Serializable;
    
    public interface Identifiable<T extends Serializable> {
        T getId();
    }
    

    CompositeKeyEntity.java

     package my.app.hibernate;
    
     import java.io.Serializable;
    
     public interface CompositeKeyEntity<T extends Serializable> extends Identifiable<T> {
     }
    

    SingleKeyEntity.java

    package my.app.hibernate;
    
    import java.io.Serializable;
    
    public interface SingleKeyEntity<T extends Serializable> extends Identifiable<T> {
    }
    

    AssignedIdentityGenerator.java

    package my.app.hibernate;
    
    import java.io.Serializable;
    import java.lang.reflect.Field;
    import java.util.Arrays;
    import java.util.List;
    
    import org.hibernate.Criteria;
    import org.hibernate.criterion.Projections;
    import org.hibernate.criterion.Restrictions;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.id.IdentityGenerator;
    import org.hibernate.internal.CriteriaImpl;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.security.util.FieldUtils;
    
    public class AssignedIdentityGenerator extends IdentityGenerator {
        private static final String ID_FIELD_NAME = "id";
        private final Logger LOG = LoggerFactory.getLogger(this.getClass());
        private Field sequenceField;
        private String entityClassName;
    
        @Override
        public Serializable generate(SessionImplementor session, Object obj) {
            @SuppressWarnings("unchecked")
            Identifiable<Serializable> identifiable = (Identifiable<Serializable>)obj;
    
            entityClassName = obj.getClass().getName();
            Criteria criteria = new CriteriaImpl(entityClassName, session);
            criteria.setReadOnly(true);
            Object toSet = null;
    
            if (identifiable instanceof CompositeKeyEntity) {
                Serializable id = identifiable.getId();
                if (id != null) {
                    String embaddebleClassName = id.getClass().getName();
                    buildCriteriaForEmbeddedId(id, embaddebleClassName, criteria);
                    toSet = id;
                }
            } else if (obj instanceof SingleKeyEntity) {
                toSet = identifiable;
                sequenceField = FieldUtils.getField(identifiable.getClass(), ID_FIELD_NAME);
                buildCriteriaForSingleId(criteria);
            }
    
            Number one = castToSequenceNumberType(1L);
            Number value = (Number) criteria.uniqueResult();
    
            if(value != null) {
                value = castToSequenceNumberType(value.longValue() + one.longValue());
    
                setFieldValue(sequenceField, value, toSet);
            } else {
                value = one;
                setFieldValue(sequenceField, value, toSet);
            }
    
            return identifiable.getId();
        }
    
        private void buildCriteriaForSingleId(Criteria criteria) {
            criteria.setProjection(Projections.max(ID_FIELD_NAME).as("seq"));
        }
    
        private void buildCriteriaForEmbeddedId(Serializable id, String embaddebleClassName, Criteria criteria) {
            List<Field> fields = Arrays.asList(id.getClass().getDeclaredFields());
    
            class Utils {
                Field field;
                boolean numberFound = false;
            }
            final Utils utils = new Utils();
    
            for (Field field : fields) {
                if ("serialVersionUID".equals(field.getName()) || "$jacocoData".equals(field.getName())) {
                    continue;
                }
    
                if (Number.class.isAssignableFrom(field.getType())) {
                    if (utils.numberFound) {
                        throw new IllegalArgumentException(
                                embaddebleClassName + " has more then one sequence field: " + field.getName() + ", "
                                        + utils.field.getName() + ",...");
                    }
    
                    utils.numberFound = true;
                    utils.field = field;
                    sequenceField = field;
    
                    criteria.setProjection(Projections.max(ID_FIELD_NAME + "." + sequenceField.getName()).as("seq"));
                } else {
                    criteria.add(Restrictions.eq(ID_FIELD_NAME + "." + field.getName(), getFieldValue(field, id)));
                }
            }
        }
    
        private Number castToSequenceNumberType(Number n) {
            return (Number) sequenceField.getType().cast(n);
        }
    
        private void setFieldValue(Field field, Object value, Object to) {
            try {
                field.setAccessible(true);
                field.set(to, value);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                LOG.error(e.getMessage(), e);
            }
        }
    
        private Object getFieldValue(Field field, Object from) {
            try {
                field.setAccessible(true);
                return field.get(from);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                LOG.error(e.getMessage(), e);
            }
    
            return null;
        }
    }
    

    客户.java

    package my.app.entities;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import org.hibernate.annotations.GenericGenerator;
    
    import my.app.hibernate.SingleKeyEntity;
    
    @Entity(name = "whatever_entity_name")
    @GenericGenerator(name = "WHATEVER_NAMED_GENERATOR", strategy = "my.app.hibernate.AssignedIdentityGenerator")
    public class Customer implements SingleKeyEntity<Long> {
    
        @Id
        @GeneratedValue(generator = "WHATEVER_NAMED_GENERATOR")
        private Long id;
        @Column(nullable = false)
        private String name;
    }
    

    CustomerItemsId.java(Item.java 省略,因为它遵循 SingleKeyEntity 示例)

    package my.app.entities;
    
    import javax.persistence.Embeddable;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    
    @Embeddable
    public class CustomerItemsId implements Serializable {
        private static final long serialVersionUID = 1L; //generate one
    
        @ManyToOne
        @JoinColumn(name = "customer_id")
        private Customer customer;
        @ManyToOne
        @JoinColumn(name = "item_id")
        private Item item;
        private Long seq; //name as you wish
    }
    

    CustomerItems.java

    package my.app.entities;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import org.hibernate.annotations.GenericGenerator;
    
    import my.app.hibernate.CompositeKeyEntity;
    
    @Entity(name = "whatever_entity_name")
    @GenericGenerator(name = "WHATEVER_NAMED_GENERATOR", strategy = "my.app.hibernate.AssignedIdentityGenerator")
    public class CustomerItems implements CompositeKeyEntity<CustomerItemsId> {
    
        @GeneratedValue(generator = "WHATEVER_NAMED_GENERATOR")
        private CustomerItems id;
        @Column(nullable = false)
        private String randomColumn1;
        @Column(nullable = false)
        private String randomColumn2;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      • 2023-04-03
      • 1970-01-01
      • 2012-10-22
      相关资源
      最近更新 更多