在可嵌入/嵌入式 id 中使用休眠序列生成器



在Hibernate中,它是否可能使用@GeneratedValue和@SequenceGenerator@EmbeddedId或@Embeddable?

我需要嵌入式 id(或 @embeddable)的字符串序列生成器。

我在我的项目中使用它,到目前为止,它非常令人满意,零序列。它使用"选择 max(id) + 1"。适用于单键或复合键:

可识别.java

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

复合键实体.java

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

单键实体.java

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

分配身份生成器.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
}

客户项目.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;
}

相关内容

  • 没有找到相关文章

最新更新