web-dev-qa-db-fra.com

Mise à niveau d'Hibernate vers la version 5.2 - Création de Session Factory et remplacement de PersistentClass pour obtenir les propriétés de classe d'entité

Je suis en train de mettre à niveau ma version d'Hibernate vers la dernière version 5.2.10. J'ai remplacé mon code dans HibernateUtil pour la création de SessionFactory.

4.3.11.Final (Previous) :

 public class HibernateUtil {
   private HibernateUtil() {}

   private static SessionFactory sessionFactory;

    private static Configuration configuration;

    public static Configuration getConfiguration() {
        return configuration;
    }
    private static SessionFactory buildSessionFactory() {
        try {
                     if(sessionFactory == null) {
                        configuration = new Configuration();
                        configuration.configure("hibernate.cfg.xml");
                        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                                .applySettings(configuration.getProperties()).build();
                        sessionFactory = configuration
                                .buildSessionFactory(serviceRegistry);
                     }
            return sessionFactory;
        }
        catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }

    }
    public static SessionFactory getSessionFactory() {
        return buildSessionFactory();
    }

    public static Session getSession() {
        Session hibernateSession = getSessionFactory().getCurrentSession();
        return hibernateSession;
      }

    public static void shutdown() {
       getSessionFactory().close();
    }
}

5.2.10 Final (Nouveau):

public class HibernateUtil {
  private static StandardServiceRegistry registry;
  private static SessionFactory sessionFactory;

   public static SessionFactory getSessionFactory() {
        return buildSessionFactory();
   }

  public static SessionFactory buildSessionFactory() {
    if (sessionFactory == null) {
      try {
        registry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
        MetadataSources sources = new MetadataSources(registry);
        Metadata metadata = sources.getMetadataBuilder().build();
        sessionFactory = metadata.getSessionFactoryBuilder().build();
      } catch (Exception e) {
        e.printStackTrace();
        shutdown();
      }
    }
    return sessionFactory;
  }

public static Session getSession() {
        Session hibernateSession = getSessionFactory().getCurrentSession();
        return hibernateSession;
      }

  public static void shutdown() {
    if (registry != null) {
      StandardServiceRegistryBuilder.destroy(registry);
    }
  }
}

Maintenant, j'ai une méthode qui me chercherait la liste des noms de colonnes en passant le nom de la table DB en tant que chaîne. Je l'ai fait comme ça avant dans 4.3.11.Final:

public static List<String> getColumnNames(String tableName) {

        List<String> columnList=null;

        Map<String, ClassMetadata> map = HibernateUtil.getSessionFactory().getAllClassMetadata();
        Iterator<Entry<String, ClassMetadata>>  itr =  map.entrySet().iterator();

        while(itr.hasNext()){

            ClassMetadata classMetaData = itr.next().getValue();
            AbstractEntityPersister aep = (AbstractEntityPersister) classMetaData;

            if(aep.getTableName().split("\\.")[1].equalsIgnoreCase(tableName)){

                columnList = new ArrayList<String>();
                String[] propertyNames = classMetaData.getPropertyNames();

                for(String property : propertyNames){
                        try {
                            PersistentClass persistentClass = HibernateUtil .getConfiguration().getClassMapping(classMetaData.getEntityName());
                            String clmName =  ((Column) persistentClass.getProperty(property).getColumnIterator().next()).getName();
                            columnList.add(clmName);
                        } catch(NoSuchElementException e){
                            log.error("Element not found idenfied as : "+property);
                        } catch(Exception e){
                            log.error(e.getMessage());
                        }
                }
                break;
            }
        }

        return columnList;
    }

Désormais, après la mise à niveau, la méthode getAllClassMetadata est obsolète et il est difficile d’obtenir l’objet PersistentClass. J'ai vu une question similaire ici mais je ne pouvais pas trouver exactement la solution. Quelle partie de mon code actuel dois-je modifier pour que ma méthode getColumnNames () fonctionne exactement comme avant? Je me suis référé à la documentation et il est dit d’utiliser plutôt la fonction EntityManagerFactory.getMetamodel() mais je ne trouve pas d’exemples de référence appropriés. De plus, devrai-je modifier le mécanisme de création de SessionFactory pour cela?

7
Hasan K

Enfin, je l'ai remercié pour l'article de Vlad. J'ai pris le code intégrateur sans aucune modification et modifié ma méthode HibernateUtil et la méthode getColumns(). Alors voici mon code:

Création de SessionFactory:

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    public static SessionFactory getSessionFactory() {
        return buildSessionFactory();
    }

    private static SessionFactory buildSessionFactory() {
        final BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().enableAutoClose()
                .applyIntegrator(MetadataExtractorIntegrator.INSTANCE).build();

        final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry).configure().build();
        return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
    }

    public static Session getSession() {
        Session hibernateSession = getSessionFactory().getCurrentSession();
        return hibernateSession;
    }

    public static void shutdown() {
        getSessionFactory().close();
    }
}

Extracteur de métadonnées (Obtenir les noms de colonnes):

public static List<String> getColumnNames(String tableName) {

    List<String> columnList = new ArrayList<>();

    for (Namespace namespace : MetadataExtractorIntegrator.INSTANCE.getDatabase().getNamespaces()) {
        for (Table table : namespace.getTables()) {
            if (table.getName().equalsIgnoreCase(lookupTableName)) {
                Iterator<Column> iterator = table.getColumnIterator();
                while (iterator.hasNext()) {
                    columnList.add(iterator.next().getName());
                }
                break;
            }
        }
        if (!columnList.isEmpty())
            break;
    }
    return columnList;
}
2
Hasan K

Excellente question. En fait, cela m'a tellement plu que j'ai écrit un article à ce sujet .

Premièrement, nous devons créer une nouvelle Integrator:

public class MetadataExtractorIntegrator 
    implements org.hibernate.integrator.spi.Integrator {

    public static final MetadataExtractorIntegrator INSTANCE = 
        new MetadataExtractorIntegrator();

    private Database database;

    @Override
    public void integrate(
            Metadata metadata,
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {

        database = metadata.getDatabase();
    }

    @Override
    public void disintegrate(
        SessionFactoryImplementor sessionFactory,
        SessionFactoryServiceRegistry serviceRegistry) {

    }

    public Database getDatabase() {
        return database;
    }
}

Ensuite, nous pouvons simplement configurer Hibernate pour l’utiliser.

Si vous utilisez le mécanisme d'amorçage Hibernate, vous pouvez l'ajouter comme ceci:

final BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder();
bsrb.enableAutoClose();

Integrator integrator = integrator();
if (integrator != null) {
    bsrb.applyIntegrator( integrator );
}

final BootstrapServiceRegistry bsr = bsrb.build();

final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(bsr);

Si vous démarrez avec JPA, vous pouvez le faire comme suit:

protected EntityManagerFactory newEntityManagerFactory() {
    PersistenceUnitInfo persistenceUnitInfo = persistenceUnitInfo(
        getClass().getSimpleName()
    );

    Map<String, Object> configuration = new HashMap<>();


    configuration.put("hibernate.integrator_provider", 
        (IntegratorProvider) () -> Collections.singletonList( MetadataExtractorIntegrator.INSTANCE )
    );

    EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl(
            new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration
    );
    return entityManagerFactoryBuilder.build();
}

Maintenant, lors de l'exécution du test suivant:

for(Namespace namespace : MetadataExtractorIntegrator.INSTANCE
    .getDatabase()
    .getNamespaces()) {

    for( Table table : namespace.getTables()) {
        LOGGER.info( "Table {} has the following columns: {}",
             table,
             StreamSupport.stream(
                Spliterators.spliteratorUnknownSize( 
                    table.getColumnIterator(), 
                    Spliterator.ORDERED
                ), 
                false
            )
            .collect( Collectors.toList()) 
        );
    }
}

Hibernate affiche toutes les tables actuellement mappées dans le journal:

Table org.hibernate.mapping.Table(post) has the following columns: [
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(title), 
    org.hibernate.mapping.Column(version)
]
Table org.hibernate.mapping.Table(post_comment) has the following columns: [
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(review), 
    org.hibernate.mapping.Column(version), 
    org.hibernate.mapping.Column(post_id)
]
Table org.hibernate.mapping.Table(post_details) has the following columns: [
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(created_by), 
    org.hibernate.mapping.Column(created_on), 
    org.hibernate.mapping.Column(version)
]
Table org.hibernate.mapping.Table(post_tag) has the following columns: [
    org.hibernate.mapping.Column(post_id), 
    org.hibernate.mapping.Column(tag_id)
]
Table org.hibernate.mapping.Table(tag) has the following columns: [
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(name), 
    org.hibernate.mapping.Column(version)
]

C'est tout!

4
Vlad Mihalcea

Un moyen plus facile d’obtenir un nom de colonne avec hibernate 5

final AbstractEntityPersister classMetadata = (AbstractEntityPersister) sessionFactory.getClassMetadata(clazz)
final String[] names = classMetadata.getPropertyColumnNames(property)
0
jpozorio