美文网首页
SpringBoot集成Jpa使用Hibernate生成表字段乱

SpringBoot集成Jpa使用Hibernate生成表字段乱

作者: 静美书斋 | 来源:发表于2023-10-16 20:23 被阅读0次

    环境

    • SpringBoot 2.7.4
    • JDK15
    • 自动依赖(hibernate-core 5.6.11.Final)等
    • IDEA2023.2.2 社区版

    本地代码目录示例

    新增两个文件
    • 新增两个文件,org目录与cn目录对齐;
    • 文件1:PropertyContainer,修改其中属性集合从TreeMap更改为ListedHashMap;
    • 文件2:InheritanceState,兼容当实体继承有父类时,自定义子父类中的表字段顺序(需根据父类属性进行调整)。

    yml配置文件中关于jpa配置

    spring:
      #配置自动建表:update:没有表新建,有表更新操作,控制台显示建表语句
      jpa:
        hibernate:
          ddl-auto: update
          naming:
            physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
        show-sql: true
        # spring.jpa.open-in-view 属性被默认启用,需要手动配置该属性,去掉这个警告
        # open-in-view 是指延时加载的一些属性数据,可以在页面展现的时候,保持session不关闭,从而保证能在页面进行延时加载
        open-in-view: false
    

    PropertyContainer.java示例

    package org.hibernate.cfg;
    
    import java.util.*;
    import javax.persistence.Access;
    import javax.persistence.ManyToMany;
    import javax.persistence.ManyToOne;
    import javax.persistence.OneToMany;
    import javax.persistence.OneToOne;
    import javax.persistence.Transient;
    
    import org.hibernate.AnnotationException;
    import org.hibernate.annotations.Any;
    import org.hibernate.annotations.ManyToAny;
    import org.hibernate.annotations.Target;
    import org.hibernate.annotations.Type;
    import org.hibernate.annotations.common.reflection.XClass;
    import org.hibernate.annotations.common.reflection.XProperty;
    import org.hibernate.boot.MappingException;
    import org.hibernate.boot.jaxb.Origin;
    import org.hibernate.boot.jaxb.SourceType;
    import org.hibernate.cfg.annotations.HCANNHelper;
    import org.hibernate.internal.CoreMessageLogger;
    import org.hibernate.internal.util.StringHelper;
    import org.hibernate.internal.util.collections.CollectionHelper;
    import org.jboss.logging.Logger;
    
    /**
     * SpringBoot Jpa按照顺序生成数据库表字段
     * 依赖包见:hibernate-core-5.6.11.Final.jar
     * 源码参见:org.hibernate.cfg.PropertyContainer
     * 修改:将全部TreeMap修改为LinkedHashMap即可。
     * 说明:由于Entity存在继承BaseModel基类,数据库表中先以基类后以子类进行排序
     *
     * @since 2023-09-23
     */
    class PropertyContainer
    {
        private static final CoreMessageLogger LOG = (CoreMessageLogger) Logger.getMessageLogger(CoreMessageLogger.class, PropertyContainer.class.getName());
        private final XClass xClass;
        private final XClass entityAtStake;
        private final AccessType classLevelAccessType;
        private final List<XProperty> persistentAttributes;
    
        PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType)
        {
            this.xClass = clazz;
            this.entityAtStake = entityAtStake;
            if (defaultClassLevelAccessType == AccessType.DEFAULT)
            {
                defaultClassLevelAccessType = AccessType.PROPERTY;
            }
    
            AccessType localClassLevelAccessType = this.determineLocalClassDefinedAccessStrategy();
    
            assert localClassLevelAccessType != null;
    
            this.classLevelAccessType = localClassLevelAccessType != AccessType.DEFAULT ? localClassLevelAccessType : defaultClassLevelAccessType;
    
            assert this.classLevelAccessType == AccessType.FIELD || this.classLevelAccessType == AccessType.PROPERTY;
    
            List<XProperty> fields = this.xClass.getDeclaredProperties(AccessType.FIELD.getType());
            List<XProperty> getters = this.xClass.getDeclaredProperties(AccessType.PROPERTY.getType());
            this.preFilter(fields, getters);
            Map<String, XProperty> persistentAttributesFromGetters = new HashMap();
            LinkedHashMap<String, XProperty> localAttributeMap = new LinkedHashMap();
            collectPersistentAttributesUsingLocalAccessType(this.xClass, localAttributeMap, persistentAttributesFromGetters, fields, getters);
            collectPersistentAttributesUsingClassLevelAccessType(this.xClass, this.classLevelAccessType, localAttributeMap, persistentAttributesFromGetters, fields, getters);
            this.persistentAttributes = verifyAndInitializePersistentAttributes(this.xClass, localAttributeMap);
        }
    
        private void preFilter(List<XProperty> fields, List<XProperty> getters)
        {
            Iterator<XProperty> propertyIterator = fields.iterator();
    
            XProperty property;
            while (propertyIterator.hasNext())
            {
                property = (XProperty) propertyIterator.next();
                if (mustBeSkipped(property))
                {
                    propertyIterator.remove();
                }
            }
    
            propertyIterator = getters.iterator();
    
            while (propertyIterator.hasNext())
            {
                property = (XProperty) propertyIterator.next();
                if (mustBeSkipped(property))
                {
                    propertyIterator.remove();
                }
            }
    
        }
    
        private static void collectPersistentAttributesUsingLocalAccessType(XClass xClass, LinkedHashMap<String, XProperty> persistentAttributeMap, Map<String, XProperty> persistentAttributesFromGetters, List<XProperty> fields, List<XProperty> getters)
        {
            Iterator<XProperty> propertyIterator = fields.iterator();
    
            XProperty xProperty;
            Access localAccessAnnotation;
            while (propertyIterator.hasNext())
            {
                xProperty = (XProperty) propertyIterator.next();
                localAccessAnnotation = (Access) xProperty.getAnnotation(Access.class);
                if (localAccessAnnotation != null && localAccessAnnotation.value() == javax.persistence.AccessType.FIELD)
                {
                    propertyIterator.remove();
                    persistentAttributeMap.put(xProperty.getName(), xProperty);
                }
            }
    
            propertyIterator = getters.iterator();
    
            while (propertyIterator.hasNext())
            {
                xProperty = (XProperty) propertyIterator.next();
                localAccessAnnotation = (Access) xProperty.getAnnotation(Access.class);
                if (localAccessAnnotation != null && localAccessAnnotation.value() == javax.persistence.AccessType.PROPERTY)
                {
                    propertyIterator.remove();
                    String name = xProperty.getName();
                    XProperty previous = (XProperty) persistentAttributesFromGetters.get(name);
                    if (previous != null)
                    {
                        throw new MappingException(LOG.ambiguousPropertyMethods(xClass.getName(), HCANNHelper.annotatedElementSignature(previous), HCANNHelper.annotatedElementSignature(xProperty)), new Origin(SourceType.ANNOTATION, xClass.getName()));
                    }
    
                    persistentAttributeMap.put(name, xProperty);
                    persistentAttributesFromGetters.put(name, xProperty);
                }
            }
    
        }
    
        private static void collectPersistentAttributesUsingClassLevelAccessType(XClass xClass, AccessType classLevelAccessType, LinkedHashMap<String, XProperty> persistentAttributeMap, Map<String, XProperty> persistentAttributesFromGetters, List<XProperty> fields, List<XProperty> getters)
        {
            Iterator var6;
            XProperty getter;
            if (classLevelAccessType == AccessType.FIELD)
            {
                var6 = fields.iterator();
    
                while (var6.hasNext())
                {
                    getter = (XProperty) var6.next();
                    if (!persistentAttributeMap.containsKey(getter.getName()))
                    {
                        persistentAttributeMap.put(getter.getName(), getter);
                    }
                }
            }
            else
            {
                var6 = getters.iterator();
    
                while (var6.hasNext())
                {
                    getter = (XProperty) var6.next();
                    String name = getter.getName();
                    XProperty previous = (XProperty) persistentAttributesFromGetters.get(name);
                    if (previous != null)
                    {
                        throw new MappingException(LOG.ambiguousPropertyMethods(xClass.getName(), HCANNHelper.annotatedElementSignature(previous), HCANNHelper.annotatedElementSignature(getter)), new Origin(SourceType.ANNOTATION, xClass.getName()));
                    }
    
                    if (!persistentAttributeMap.containsKey(name))
                    {
                        persistentAttributeMap.put(getter.getName(), getter);
                        persistentAttributesFromGetters.put(name, getter);
                    }
                }
            }
    
        }
    
        public XClass getEntityAtStake()
        {
            return this.entityAtStake;
        }
    
        public XClass getDeclaringClass()
        {
            return this.xClass;
        }
    
        public AccessType getClassLevelAccessType()
        {
            return this.classLevelAccessType;
        }
    
        /**
         * @deprecated
         */
        @Deprecated
        public Collection<XProperty> getProperties()
        {
            return Collections.unmodifiableCollection(this.persistentAttributes);
        }
    
        public Iterable<XProperty> propertyIterator()
        {
            return this.persistentAttributes;
        }
    
        private static List<XProperty> verifyAndInitializePersistentAttributes(XClass xClass, Map<String, XProperty> localAttributeMap)
        {
            ArrayList<XProperty> output = new ArrayList(localAttributeMap.size());
            Iterator var3 = localAttributeMap.values().iterator();
    
            while (var3.hasNext())
            {
                XProperty xProperty = (XProperty) var3.next();
                if (!xProperty.isTypeResolved() && !discoverTypeWithoutReflection(xProperty))
                {
                    String msg = "Property " + StringHelper.qualify(xClass.getName(), xProperty.getName()) + " has an unbound type and no explicit target entity. Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
                    throw new AnnotationException(msg);
                }
    
                output.add(xProperty);
            }
    
            return CollectionHelper.toSmallList(output);
        }
    
        private AccessType determineLocalClassDefinedAccessStrategy()
        {
            AccessType hibernateDefinedAccessType = AccessType.DEFAULT;
            AccessType jpaDefinedAccessType = AccessType.DEFAULT;
            org.hibernate.annotations.AccessType accessType = (org.hibernate.annotations.AccessType) this.xClass.getAnnotation(org.hibernate.annotations.AccessType.class);
            if (accessType != null)
            {
                hibernateDefinedAccessType = AccessType.getAccessStrategy(accessType.value());
            }
    
            Access access = (Access) this.xClass.getAnnotation(Access.class);
            if (access != null)
            {
                jpaDefinedAccessType = AccessType.getAccessStrategy(access.value());
            }
    
            if (hibernateDefinedAccessType != AccessType.DEFAULT && jpaDefinedAccessType != AccessType.DEFAULT && hibernateDefinedAccessType != jpaDefinedAccessType)
            {
                throw new org.hibernate.MappingException("@AccessType and @Access specified with contradicting values. Use of @Access only is recommended. ");
            }
            else
            {
                AccessType classDefinedAccessType;
                if (hibernateDefinedAccessType != AccessType.DEFAULT)
                {
                    classDefinedAccessType = hibernateDefinedAccessType;
                }
                else
                {
                    classDefinedAccessType = jpaDefinedAccessType;
                }
    
                return classDefinedAccessType;
            }
        }
    
        private static boolean discoverTypeWithoutReflection(XProperty p)
        {
            if (p.isAnnotationPresent(OneToOne.class) && !((OneToOne) p.getAnnotation(OneToOne.class)).targetEntity().equals(Void.TYPE))
            {
                return true;
            }
            else if (p.isAnnotationPresent(OneToMany.class) && !((OneToMany) p.getAnnotation(OneToMany.class)).targetEntity().equals(Void.TYPE))
            {
                return true;
            }
            else if (p.isAnnotationPresent(ManyToOne.class) && !((ManyToOne) p.getAnnotation(ManyToOne.class)).targetEntity().equals(Void.TYPE))
            {
                return true;
            }
            else if (p.isAnnotationPresent(ManyToMany.class) && !((ManyToMany) p.getAnnotation(ManyToMany.class)).targetEntity().equals(Void.TYPE))
            {
                return true;
            }
            else if (p.isAnnotationPresent(Any.class))
            {
                return true;
            }
            else if (p.isAnnotationPresent(ManyToAny.class))
            {
                if (!p.isCollection() && !p.isArray())
                {
                    throw new AnnotationException("@ManyToAny used on a non collection non array property: " + p.getName());
                }
                else
                {
                    return true;
                }
            }
            else if (p.isAnnotationPresent(Type.class))
            {
                return true;
            }
            else
            {
                return p.isAnnotationPresent(Target.class);
            }
        }
    
        private static boolean mustBeSkipped(XProperty property)
        {
            return property.isAnnotationPresent(Transient.class) || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals(property.getType().getName());
        }
    }
    
    

    InheritanceState.java示例

    /*
     * Hibernate, Relational Persistence for Idiomatic Java
     *
     * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
     * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
     */
    package org.hibernate.cfg;
    
    import org.hibernate.AnnotationException;
    import org.hibernate.annotations.common.reflection.XAnnotatedElement;
    import org.hibernate.annotations.common.reflection.XClass;
    import org.hibernate.annotations.common.reflection.XProperty;
    import org.hibernate.boot.spi.MetadataBuildingContext;
    import org.hibernate.cfg.annotations.EntityBinder;
    import org.hibernate.mapping.PersistentClass;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    
    /**
     * SpringBoot Jpa按照顺序生成数据库表字段
     * 1.当实体类继承有父类时,重新自定义生成表顺序,配合{@link PropertyContainer}使用!
     * 2.此类依赖父类“cn.keyidea.common.bean.BaseModel”全路径地址,移动后请更改!
     * <p>
     * 依赖包见:hibernate-core-5.6.11.Final.jar
     * 源码参见:org.hibernate.cfg.InheritanceState
     *
     * @since 2023-10-17
     */
    public class InheritanceState {
    
        private final static Logger logger = LoggerFactory.getLogger(InheritanceState.class);
    
        private XClass clazz;
    
        /**
         * Has sibling (either mappedsuperclass entity)
         */
        private boolean hasSiblings = false;
    
        /**
         * a mother entity is available
         */
        private boolean hasParents = false;
        private InheritanceType type;
        private boolean isEmbeddableSuperclass = false;
        private Map<XClass, InheritanceState> inheritanceStatePerClass;
        private List<XClass> classesToProcessForMappedSuperclass = new ArrayList<XClass>();
        private MetadataBuildingContext buildingContext;
        private AccessType accessType;
        private ElementsToProcess elementsToProcess;
        private Boolean hasIdClassOrEmbeddedId;
    
        public InheritanceState(
                XClass clazz,
                Map<XClass, InheritanceState> inheritanceStatePerClass,
                MetadataBuildingContext buildingContext) {
            this.setClazz(clazz);
            this.buildingContext = buildingContext;
            this.inheritanceStatePerClass = inheritanceStatePerClass;
            extractInheritanceType();
        }
    
        private void extractInheritanceType() {
            XAnnotatedElement element = getClazz();
            Inheritance inhAnn = element.getAnnotation(Inheritance.class);
            MappedSuperclass mappedSuperClass = element.getAnnotation(MappedSuperclass.class);
            if (mappedSuperClass != null) {
                setEmbeddableSuperclass(true);
                setType(inhAnn == null ? null : inhAnn.strategy());
            } else {
                setType(inhAnn == null ? InheritanceType.SINGLE_TABLE : inhAnn.strategy());
            }
        }
    
        boolean hasTable() {
            return !hasParents() || !InheritanceType.SINGLE_TABLE.equals(getType());
        }
    
        boolean hasDenormalizedTable() {
            return hasParents() && InheritanceType.TABLE_PER_CLASS.equals(getType());
        }
    
        public static InheritanceState getInheritanceStateOfSuperEntity(
                XClass clazz, Map<XClass, InheritanceState> states
        ) {
            XClass superclass = clazz;
            do {
                superclass = superclass.getSuperclass();
                InheritanceState currentState = states.get(superclass);
                if (currentState != null && !currentState.isEmbeddableSuperclass()) {
                    return currentState;
                }
            }
            while (superclass != null && !Object.class.getName().equals(superclass.getName()));
            return null;
        }
    
        public static InheritanceState getSuperclassInheritanceState(XClass clazz, Map<XClass, InheritanceState> states) {
            XClass superclass = clazz;
            do {
                superclass = superclass.getSuperclass();
                InheritanceState currentState = states.get(superclass);
                if (currentState != null) {
                    return currentState;
                }
            }
            while (superclass != null && !Object.class.getName().equals(superclass.getName()));
            return null;
        }
    
        public XClass getClazz() {
            return clazz;
        }
    
        public void setClazz(XClass clazz) {
            this.clazz = clazz;
        }
    
        public boolean hasSiblings() {
            return hasSiblings;
        }
    
        public void setHasSiblings(boolean hasSiblings) {
            this.hasSiblings = hasSiblings;
        }
    
        public boolean hasParents() {
            return hasParents;
        }
    
        public void setHasParents(boolean hasParents) {
            this.hasParents = hasParents;
        }
    
        public InheritanceType getType() {
            return type;
        }
    
        public void setType(InheritanceType type) {
            this.type = type;
        }
    
        public boolean isEmbeddableSuperclass() {
            return isEmbeddableSuperclass;
        }
    
        public void setEmbeddableSuperclass(boolean embeddableSuperclass) {
            isEmbeddableSuperclass = embeddableSuperclass;
        }
    
        void postProcess(PersistentClass persistenceClass, EntityBinder entityBinder) {
            //make sure we run elements to process
            getElementsToProcess();
            addMappedSuperClassInMetadata(persistenceClass);
            entityBinder.setPropertyAccessType(accessType);
        }
    
        public XClass getClassWithIdClass(boolean evenIfSubclass) {
            if (!evenIfSubclass && hasParents()) {
                return null;
            }
            if (clazz.isAnnotationPresent(IdClass.class)) {
                return clazz;
            } else {
                InheritanceState state = InheritanceState.getSuperclassInheritanceState(clazz, inheritanceStatePerClass);
                if (state != null) {
                    return state.getClassWithIdClass(true);
                } else {
                    return null;
                }
            }
        }
    
        public Boolean hasIdClassOrEmbeddedId() {
            if (hasIdClassOrEmbeddedId == null) {
                hasIdClassOrEmbeddedId = false;
                if (getClassWithIdClass(true) != null) {
                    hasIdClassOrEmbeddedId = true;
                } else {
                    final ElementsToProcess process = getElementsToProcess();
                    for (PropertyData property : process.getElements()) {
                        if (property.getProperty().isAnnotationPresent(EmbeddedId.class)) {
                            hasIdClassOrEmbeddedId = true;
                            break;
                        }
                    }
                }
            }
            return hasIdClassOrEmbeddedId;
        }
    
        /*
         * Get the annotated elements and determine access type from hierarchy, guessing from @Id or @EmbeddedId presence if not
         * specified.
         * Change EntityBinder by side effect
         */
    
        public ElementsToProcess getElementsToProcess() {
            if (elementsToProcess == null) {
                InheritanceState inheritanceState = inheritanceStatePerClass.get(clazz);
                assert !inheritanceState.isEmbeddableSuperclass();
    
    
                getMappedSuperclassesTillNextEntityOrdered();
    
                accessType = determineDefaultAccessType();
    
                ArrayList<PropertyData> elements = new ArrayList<PropertyData>();
                int idPropertyCount = 0;
    
                for (XClass classToProcessForMappedSuperclass : classesToProcessForMappedSuperclass) {
                    PropertyContainer propertyContainer = new PropertyContainer(
                            classToProcessForMappedSuperclass,
                            clazz,
                            accessType
                    );
                    int currentIdPropertyCount = AnnotationBinder.addElementsOfClass(
                            elements,
                            propertyContainer,
                            buildingContext
                    );
                    idPropertyCount += currentIdPropertyCount;
                }
    
                if (idPropertyCount == 0 && !inheritanceState.hasParents()) {
                    throw new AnnotationException("No identifier specified for entity: " + clazz.getName());
                }
                elements.trimToSize();
    
                // 自定义排序字段
                if (Objects.equals(elements.get(0).getDeclaringClass().toString(), "cn.keyidea.common.bean.BaseModel")) {
                    // logger.info("此表继承父类:{}", elements.get(5).getDeclaringClass().toString());
                    for (int i = 0; i < 4; i++) {
                        // 由于BaseModel父类中有4个元素,因此循环4次,将父类中除id之外的四个属性移到末尾
                        moveElementToLast(elements, 1);
                    }
                } else {
                    // logger.info("此表不继承父类:{}", elements.get(5).getDeclaringClass().toString());
                }
    
                // logger.info("element={}", elements);
                // for (PropertyData element : elements) {
                //     logger.info("表字段属性:{}", element.getPropertyName());
                // }
    
                elementsToProcess = new ElementsToProcess(elements, idPropertyCount);
            }
            return elementsToProcess;
        }
    
        private AccessType determineDefaultAccessType() {
            for (XClass xclass = clazz; xclass != null; xclass = xclass.getSuperclass()) {
                if ((xclass.getSuperclass() == null || Object.class.getName().equals(xclass.getSuperclass().getName()))
                        && (xclass.isAnnotationPresent(Entity.class) || xclass.isAnnotationPresent(MappedSuperclass.class))
                        && xclass.isAnnotationPresent(Access.class)) {
                    return AccessType.getAccessStrategy(xclass.getAnnotation(Access.class).value());
                }
            }
            // Guess from identifier.
            // FIX: Shouldn't this be determined by the first attribute (i.e., field or property) with annotations, but without an
            //      explicit Access annotation, according to JPA 2.0 spec 2.3.1: Default Access Type?
            for (XClass xclass = clazz; xclass != null && !Object.class.getName().equals(xclass.getName()); xclass = xclass.getSuperclass()) {
                if (xclass.isAnnotationPresent(Entity.class) || xclass.isAnnotationPresent(MappedSuperclass.class)) {
                    for (XProperty prop : xclass.getDeclaredProperties(AccessType.PROPERTY.getType())) {
                        final boolean isEmbeddedId = prop.isAnnotationPresent(EmbeddedId.class);
                        if (prop.isAnnotationPresent(Id.class) || isEmbeddedId) {
                            return AccessType.PROPERTY;
                        }
                    }
                    for (XProperty prop : xclass.getDeclaredProperties(AccessType.FIELD.getType())) {
                        final boolean isEmbeddedId = prop.isAnnotationPresent(EmbeddedId.class);
                        if (prop.isAnnotationPresent(Id.class) || isEmbeddedId) {
                            return AccessType.FIELD;
                        }
                    }
                }
            }
            throw new AnnotationException("No identifier specified for entity: " + clazz);
        }
    
        private void getMappedSuperclassesTillNextEntityOrdered() {
    
            //ordered to allow proper messages on properties subclassing
            XClass currentClassInHierarchy = clazz;
            InheritanceState superclassState;
            do {
                classesToProcessForMappedSuperclass.add(0, currentClassInHierarchy);
                XClass superClass = currentClassInHierarchy;
                do {
                    superClass = superClass.getSuperclass();
                    superclassState = inheritanceStatePerClass.get(superClass);
                }
                while (superClass != null
                        && !buildingContext.getBootstrapContext().getReflectionManager().equals(superClass, Object.class)
                        && superclassState == null);
    
                currentClassInHierarchy = superClass;
            }
            while (superclassState != null && superclassState.isEmbeddableSuperclass());
        }
    
        private void addMappedSuperClassInMetadata(PersistentClass persistentClass) {
            //add @MappedSuperclass in the metadata
            // classes from 0 to n-1 are @MappedSuperclass and should be linked
            org.hibernate.mapping.MappedSuperclass mappedSuperclass = null;
            final InheritanceState superEntityState =
                    InheritanceState.getInheritanceStateOfSuperEntity(clazz, inheritanceStatePerClass);
            PersistentClass superEntity =
                    superEntityState != null ?
                            buildingContext.getMetadataCollector().getEntityBinding(superEntityState.getClazz().getName()) :
                            null;
            final int lastMappedSuperclass = classesToProcessForMappedSuperclass.size() - 1;
            for (int index = 0; index < lastMappedSuperclass; index++) {
                org.hibernate.mapping.MappedSuperclass parentSuperclass = mappedSuperclass;
                final Class<?> type = buildingContext.getBootstrapContext().getReflectionManager()
                        .toClass(classesToProcessForMappedSuperclass.get(index));
                //add MappedSuperclass if not already there
                mappedSuperclass = buildingContext.getMetadataCollector().getMappedSuperclass(type);
                if (mappedSuperclass == null) {
                    mappedSuperclass = new org.hibernate.mapping.MappedSuperclass(parentSuperclass, superEntity);
                    mappedSuperclass.setMappedClass(type);
                    buildingContext.getMetadataCollector().addMappedSuperclass(type, mappedSuperclass);
                }
            }
            if (mappedSuperclass != null) {
                persistentClass.setSuperMappedSuperclass(mappedSuperclass);
            }
        }
    
        static final class ElementsToProcess {
            private final List<PropertyData> properties;
            private final int idPropertyCount;
    
            public List<PropertyData> getElements() {
                return properties;
            }
    
            public int getIdPropertyCount() {
                return idPropertyCount;
            }
    
            private ElementsToProcess(List<PropertyData> properties, int idPropertyCount) {
                this.properties = properties;
                this.idPropertyCount = idPropertyCount;
            }
        }
    
        /**
         * 将List集中中指定元素移动到最后
         *
         * @param list  集合对象
         * @param index 集合序号
         * @param <T>   返回集合
         */
        public static <T> void moveElementToLast(List<T> list, int index) {
            if (list != null && index >= 0 && index < list.size()) {
                // 移除指定位置的元素
                T element = list.remove(index);
                // 添加该元素到列表的末尾
                list.add(element);
            }
        }
    }
    

    父类BaseModel示例

    package cn.keyidea.common.bean;
    
    import cn.keyidea.common.valid.GroupChangePwd;
    import cn.keyidea.common.valid.GroupCustomWithId;
    import cn.keyidea.common.valid.GroupStatus;
    import cn.keyidea.common.valid.GroupUpdate;
    import com.alibaba.fastjson.annotation.JSONField;
    import com.baomidou.mybatisplus.annotation.FieldFill;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.SuperBuilder;
    import org.springframework.data.jpa.domain.support.AuditingEntityListener;
    
    import javax.persistence.*;
    import javax.validation.constraints.NotNull;
    import java.io.Serializable;
    import java.util.Date;
    
    
    /**
     * 实体父类
     * <p>
     * 特殊说明:
     * 继承此基类的实体类,如果使用lombok的@Data注解时,主要同时添加@EqualsAndHashCode(callSuper = true)注解
     * 1)注解@EqualsAndHashCode(callSuper = true),就是用自己的属性和从父类继承的属性来生成hashcode;
     * 2)注解@EqualsAndHashCode(callSuper = false),就是只用自己的属性来生成hashcode;
     * 3)@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集, 和@EqualsAndHashCode默认是false。
     * <p>
     * MappedSuperclass注解说明:
     * 1.@MappedSuperclass注解仅仅能标准在类上;这个注解标识在父类上面的,用来标识父类
     * 2.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,可是他的属性都将映射到其子类的数据库字段中
     * 3.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解
     * <p>
     * EntityListeners注解及相关说明:
     * EntityListeners:该注解用于指定Entity或者superclass上的回调监听类
     * AuditingEntityListener:这是一个JPA Entity Listener,用于捕获监听信息,当Entity发生持久化和更新操作时
     *
     * @date 2022-10-17
     */
    @SuperBuilder   // @SuperBuilder支持对基类成员属性的构造;如果子类继承了BaseModel,也需要使用该注解
    @AllArgsConstructor // 全参构造函数
    @NoArgsConstructor  // 空参构造函数
    @Data
    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    public class BaseModel implements Serializable
    {
    
        private static final long serialVersionUID = -7321769721953580032L;
    
        @NotNull(message = "ID不能为NUll", groups = {GroupUpdate.class, GroupChangePwd.class, GroupCustomWithId.class, GroupStatus.class})
        @ApiModelProperty(value = "主键ID", required = true, example = "1")
        @Id
        @Column(name = "id", columnDefinition = "int(10) COMMENT '自增长ID'")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
    
        @ApiModelProperty(value = "创建时间", required = false)
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        @Column(name = "create_time", updatable = false, columnDefinition = "datetime not null COMMENT '创建时间'")
        @TableField(value = "create_time", fill = FieldFill.INSERT)
        @JSONField(format = "yyyy-MM-dd HH:mm:ss")
        private Date createTime;
    
        @ApiModelProperty(value = "创建人ID", required = false)
        @Column(name = "create_by", updatable = false, columnDefinition = "int(10) not null COMMENT '创建人ID'")
        @TableField(value = "create_by", fill = FieldFill.INSERT)
        private Integer createBy;
    
        @ApiModelProperty(value = "更新时间", required = false)
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        @Column(name = "update_time", columnDefinition = "datetime COMMENT '更新时间'")
        @TableField(value = "update_time", fill = FieldFill.UPDATE)
        @JSONField(format = "yyyy-MM-dd HH:mm:ss")
        private Date updateTime;
    
        @ApiModelProperty(value = "更新人ID", required = false)
        @Column(name = "update_by", columnDefinition = "int(10) COMMENT '更新人ID'")
        @TableField(value = "update_by", fill = FieldFill.UPDATE)
        private Integer updateBy;
    
    }
    
    

    系统配置实体类示例

    package cn.keyidea.sys.entity;
    
    import cn.keyidea.common.bean.BaseModel;
    import com.baomidou.mybatisplus.annotation.TableName;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Table;
    import javax.validation.constraints.NotBlank;
    
    /**
     * 系统配置表
     *
     * @date 2022-10-17
     */
    @Data
    @EqualsAndHashCode(callSuper = true)
    @Entity
    @TableName("sys_config")
    @Table(name = "sys_config")
    @ApiModel(value = "SysConfig", description = "系统配置")
    @org.hibernate.annotations.Table(appliesTo = "sys_config", comment = "系统配置表")
    public class SysConfig extends BaseModel
    {
    
        @NotBlank(message = "配置名称不能为空")
        @ApiModelProperty(value = "配置名称", required = true, example = "名称1")
        @Column(name = "name", columnDefinition = "varchar(50) not null COMMENT '配置名称'")
        private String name;
    
        @NotBlank(message = "配置key值为空")
        @ApiModelProperty(value = "配置key值", required = true, example = "code1")
        @Column(name = "code", columnDefinition = "varchar(50) not null COMMENT '配置key值'")
        private String code;
    
        @NotBlank(message = "配置项值为空")
        @ApiModelProperty(value = "配置项值", required = true, example = "value1")
        @Column(name = "value", columnDefinition = "varchar(50) not null COMMENT '配置项值'")
        private String value;
    
        @ApiModelProperty(value = "配置项描述", required = true, example = "说明/描述")
        @Column(name = "remark", columnDefinition = "varchar(255) COMMENT '配置项描述'")
        private String remark;
    
    }
    
    

    参考

    相关文章

      网友评论

          本文标题:SpringBoot集成Jpa使用Hibernate生成表字段乱

          本文链接:https://www.haomeiwen.com/subject/rzqfidtx.html