Code example to retrieve table name for an entity

2020-03-31 08:18发布

问题:

I want to list all Database Table names for my JPA Entity model, but I can't get the correct Entity class!

EntityManagerFactory factory;
Set<EntityType<?>> entities = factory.getMetamodel().getEntities();
for (EntityType entity: entities) {
    String tableName = entity.getClass().getAnnotation(Table.class).name();
    logger.debug("Entity name  = {}", entity.getName(); //This works
    logger.debug("Entity class = {}", entity.getClass().getName()); //This returns the runtime class of the object, and not the entity class!!
    logger.debug("Entity table = {}", entity.getClass().getAnnotation(Table.class).name()); //Nothing, because it does not find the correct class
}

Output:

Entity name  = PersonEntity
Entity class = org.hibernate.jpa.internal.metamodel.EntityTypeImpl
Entity table = ........ nothing, because this works on the EntityTypeImpl and not on the PersonEnity

How do I get the Table name for the Entity Class?

回答1:

OK, so if want do this with reflection. It should be pretty easy since this runtime class have to extends your class. If it wouldn't extends your class you won't be able to use it in your application.

So you have to do something like below

    String myPackage = "com.company.";
    Class entityClass = y.getClass();
    while (!entityClass.getCanonicalName().startsWith(myPackage)) {
        entityClass = entityClass.getSuperclass();
    }
    Class classInYourPackage = entityClass;

And you should get correct (your) class.

Not tested, however that's the way it should work.

EDIT: Not sure what package will be assigned by JPA to these runtime classes. So if code above doesn't work try with getSuperclass() method on your own.



回答2:

To answer this question, we must realize that the JPA runtime type wraps the original @Entity annotated POJO. A simple test with the non-runtime class will show that the Table name is accessible:

System.out.println("Table_Name: " + MyEntity.class.getAnnotation(Table.class).name());

So the trick here is to get access to the correct entity class reference, and then call the desired functions from there.

Referring to the API for EntityTypeImpl, we can see that it inherits from AbstractType, which provides the method "getJavaType()", which returns a reference to the underlying entity class. With this knowledge, we can write the following function to get the every Entity Class associated with the current session, as well as every Table name associated with every entity.

protected void testFunc() {
    Metamodel metamodel = entityManager.getMetamodel();
    for (EntityType<?> e : metamodel.getEntities()) {
        Class<?> entityClass = e.getJavaType();
        String entityTableName = entityClass.getAnnotation(Table.class).name();
        System.out.println("Table_Name: " + entityTableName);
    }
}