【问题标题】:Get the table name from the model in Hibernate从 Hibernate 中的模型中获取表名
【发布时间】:2009-03-11 12:42:34
【问题描述】:

如何在 Hibernate 中获取模型的表名?

显然在ClassMetadata 中曾经有一个getTableName() 方法,但它已被删除。

Configuration 中有一个 getClassMapping(String entityName) 方法,但我不知道如何(或是否应该)在我的 DAO 实现中使用 Configuration。

我的 DAO 实现是 HibernateGeneralGenericDao 的子类。

更新:事实证明,我可以在没有表名的情况下做我想做的事情。但是,为了参考,我将保持问题开放(并尝试答案)。

【问题讨论】:

    标签: java hibernate


    【解决方案1】:

    这有点奇怪,但它有效:

    ClassMetadata hibernateMetadata = sessionFactory.getClassMetadata(pClassName);
    
    if (hibernateMetadata == null)
    {
        return;
    }
    
    if (hibernateMetadata instanceof AbstractEntityPersister)
    {
         AbstractEntityPersister persister = (AbstractEntityPersister) hibernateMetadata;
         String tableName = persister.getTableName();
         String[] columnNames = persister.getKeyColumnNames();
    }
    

    【讨论】:

    【解决方案2】:

    如果您使用 Table 注释,您可以执行以下操作:

    Table table = Entity.class.getAnnotation(Table.class);
    String tableName = table.name();
    

    【讨论】:

    • 我不是(老实说,我刚刚了解了注释),但这是一个好主意。谢谢。
    • 可以肯定的是,只有在每个实体上设置表注释时,这才有效。如果你不这样做,Hibernate 可以很好地工作(它从实体名称派生名称)
    • 这工作正常,但我怎样才能获得列名?
    【解决方案3】:
    Configuration cfg = new Configuration().configure();    
    cfg.addResource("com/struts/Entities/User.hbm.xml");
    cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
    Mappings m=cfg.createMappings();
    System.out.println(">> class: "+m.getClass(className));
    System.out.println("User table name:: "+m.getClass("User").getTable().getName());
    

    【讨论】:

      【解决方案4】:

      classMetadata 已弃用。

      用途:

      @PersistenceContext
      private EntityManager entityManager;
      
      public String extractTableName(final Class<?> modelClazz) {
          final MetamodelImpl metamodel = (MetamodelImpl) entityManager.getMetamodel();
          final EntityPersister entityPersister = metamodel.entityPersister(modelClazz);
          if (entityPersister instanceof SingleTableEntityPersister) {
              return ((SingleTableEntityPersister) entityPersister).getTableName();
          } else {
              throw new IllegalArgumentException(modelClazz + " does not map to a single table.");
          }
      }
      

      【讨论】:

        【解决方案5】:

        使用配置,您可以为特定类型调用 GetClassMapping() 方法,这将为您提供该类型的一些映射信息。

        (至少在 NHibernate 中是这样,但我想在 Hibernate 中也是如此)。

        【讨论】:

        • 是的,但是如何使用配置?我可以创建一个新实例吗?
        • 一些选项是在初始化期间创建一个新实例;保持它作为静态或单例;或使用反射从 SessionFactory 中获取它。完成配置后: configuration.getClassMapping("foo").getTable().getName();
        【解决方案6】:

        或在 GUI 中显示所有列和所有实体的列表,我需要动态加载表、实体、属性和列名、类型、setter、getter 甚至漂亮标签的完整列表,我就是这样做的基于@Tom Redfem 使用 java 8 流重构的解决方案:

        public void loadHibernateMetadata() throws ClassNotFoundException {
            Map<String, ClassMetadata> hibernateMetadata = sessionFactory.getAllClassMetadata();        
        
            hibernateMetadata.values()
                .stream()
                .filter(metadata -> metadata != null && metadata instanceof AbstractEntityPersister)
                .map(AbstractEntityPersister.class::cast)
                .forEach( persister -> createNewnParam(persister));
                ;
        
        }
        

        然后createNewParam方法就是:

        private void createNewParam(AbstractEntityPersister persister) {
            try {
                Class<?> $class = Class.forName(persister.getEntityName());
        
        
                List<String> getterNameRoster = Lists.newArrayList($class.getMethods())
                        .stream()
                        .filter( method -> method.getName().startsWith("get") || method.getName().startsWith("is"))
                        .map(getterName -> getterName.getName())
                        .collect(toList())
                        ;
        
                List<String> setterNameRoster = Lists.newArrayList($class.getMethods())
                        .stream()
                        .filter( method -> method.getName().startsWith("set") )
                        .map(setterName -> setterName.getName())
                        .collect(toList())
                        ;           
        
                Iterable<AttributeDefinition> attrs = persister.getAttributes();
                attrs.forEach(a -> {        
        
                    String columnName = persister.getPropertyColumnNames(a.getName())[0];
                    org.hibernate.type.Type hibernateType =persister.getPropertyType(a.getName());
        
                    Optional<String> optionalGetter = getterNameRoster.stream()
                                    .filter(getterStr -> getterStr.equalsIgnoreCase( String.format("get%s", a.getName()) ) ||
                                                         getterStr.equalsIgnoreCase( String.format("is%s", a.getName())) )
                                    .findFirst()                                
                                    ;
        
                    String getterName = optionalGetter.isPresent() ? optionalGetter.get() : new String("");
        
                    Optional<String> optionalSetter = setterNameRoster.stream()
                                        .filter(setterStr -> setterStr.equalsIgnoreCase( String.format("set%s", a.getName()) ))                 
                                        .findFirst()                                    
                                        ;
                    String setterName = optionalSetter.isPresent() ? optionalSetter.get() : new String("");
        
        
                    Param param = new Param(persister.getEntityName(), 
                                                                persister.getTableName().replaceAll("\"", "").toUpperCase(), 
                                                                columnName.replaceAll("\"", "").toUpperCase(),
                                                                a.getName(),
                                                                getterName, 
                                                                setterName, 
                                                                hibernateType.getName(), 
                                                                capitalizeFirstLetter(splitCamelCase(a.getName()))
                                                                );
                    hibernateParamList.add(param);
                    logger.debug(param.toString());
                });
        
            } catch (ClassNotFoundException e) {
                logger.error(String.format("error occured generating the params %s" , e));
            }
        }
        

        和两个 String 辅助方法来生成漂亮的标签,这可能与这篇文章无关

        private String splitCamelCase(String s) {
           return s.replaceAll(
              String.format("%s|%s|%s",
                 "(?<=[A-Z])(?=[A-Z][a-z])",
                 "(?<=[^A-Z])(?=[A-Z])",
                 "(?<=[A-Za-z])(?=[^A-Za-z])"
              ),
              " "
           );
        }
        
        private String capitalizeFirstLetter(String s) {
            return Character.toUpperCase(s.charAt(0)) + s.substring(1);
        }
        

        当然,在我的 WebAppConfig.class 中,我得到了会话工厂

        public SessionFactory sessionFactory() {
          LocalSessionFactoryBuilder builder =
                    new LocalSessionFactoryBuilder(dataSource());
          builder.addProperties(hibernateProperties());
          builder.scanPackages(new String[] { "com....model" });
          SessionFactory sessionFactory = builder.buildSessionFactory();
        
          return sessionFactory;
        

        }

        也许我们可以进一步优化流,但对我来说这非常快速和容易。

        【讨论】:

          【解决方案7】:

          【讨论】:

          • 是的,我试过了,但 ClassMetadata 似乎不包含任何有关表的信息
          【解决方案8】:

          您可以使用此功能获取项目中的每个表名称:

          public Set<String> getTablesName() {
              Set<String> names = new HashSet<>();
              SessionFactory sessionFactory = emf.unwrap(SessionFactory.class);
          
              Map<String, ClassMetadata> classMetadataMap = sessionFactory.getAllClassMetadata();
              for (ClassMetadata classMetadata : classMetadataMap.values()) {
                  AbstractEntityPersister aep = (AbstractEntityPersister) classMetadata;
                  String tableName = aep.getTableName();
                  if (StringUtils.isBlank(tableName) || StringUtils.containsWhitespace(tableName)) {
                      continue;
                  }
                  names.add(tableName);
              }
              return names;
          }
          

          【讨论】:

          • 这给出了错误org.hibernate.SessionFactory.getAllClassMetadata is no longer supported
          • 嗯,这意味着该方法已被弃用,不再起作用
          【解决方案9】:

          由于不推荐使用 getClassMetadata 方法。试试这样的。

             Configuration configuration = new Configuration();
              configuration.configure();
              
              StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
              
              Metadata = new MetadataSources(standardRegistry).getMetadataBuilder().build();
              SessionFactory sessionFactory = configuration.buildSessionFactory();
              
              String tableName=Metadata.getEntityBinding(entityName).getQualifiedTableName().toString();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-01-21
            • 2021-04-28
            • 1970-01-01
            • 2015-11-21
            • 2013-10-25
            • 2013-11-06
            • 2019-01-29
            • 1970-01-01
            相关资源
            最近更新 更多