How to retrieve mapping table name for an entity in JPA at runtime?
Is it possible to determine the native table name of an entity?
If a Table
annotation is present it's easy:
entityClass.getAnnotation(Table.class).name()
But what about if no Table
annotation is present?
Hibernate provides this information开发者_如何学运维 via the Configuration
class:
configuration.getClassMapping(entityClass.getSimpleName()).getTable().getName()
Is there something similar in JPA?
This is the method I am using with EclipseLink (no mapping file):
/**
* Returns the table name for a given entity type in the {@link EntityManager}.
* @param em
* @param entityClass
* @return
*/
public static <T> String getTableName(EntityManager em, Class<T> entityClass) {
/*
* Check if the specified class is present in the metamodel.
* Throws IllegalArgumentException if not.
*/
Metamodel meta = em.getMetamodel();
EntityType<T> entityType = meta.entity(entityClass);
//Check whether @Table annotation is present on the class.
Table t = entityClass.getAnnotation(Table.class);
String tableName = (t == null)
? entityType.getName().toUpperCase()
: t.name();
return tableName;
}
A colleague of mine found the following solution for a Spring Data JPA environment backed by Hibernate:
import org.hibernate.internal.SessionImpl;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
@Service
public class EntityClassToTableNameMapper {
@Transactional
public String[] getTableNames(EntityManager em, Class entityClass) {
Object entityExample;
try {
entityExample = entityClass.newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
SessionImpl session = em.unwrap(SessionImpl.class);
EntityPersister persister = session.getEntityPersister(null, entityExample);
if (persister instanceof AbstractEntityPersister) {
AbstractEntityPersister persisterImpl = (AbstractEntityPersister) persister;
String tableName = persisterImpl.getTableName();
String rootTableName = persisterImpl.getRootTableName();
return new String[] {rootTableName, tableName};
} else {
throw new RuntimeException("Unexpected persister type; a subtype of AbstractEntityPersister expected.");
}
}
}
If no table annotation is present (and no ORM.xml) then in JPA the table name is formed based on the class name (see the JPA spec). Hence why exactly do you need an accessor method ?
See http://www.datanucleus.org/products/accessplatform_2_0/jpa/orm/datastore_identifiers.html
If you use @Table annotation, there is no problem, as you have shown. If you don't use that annotation, then table name is the same as the class name (JPA default).
The fun starts if you use mapping file, you need to parse it and retrive table name - this is not very difficult, but demands some work. If you are afraid of performance issues then you can parse mapping file(s) once and cache all tables names.
Asking to the meta-model of the underlaying ORM is the most reliable: looking at the presence of the @Table is not enough, not only it can be overridden by XML configuration (e.g. orm.xml) but with JOINED strategy, the @Table may be on a super-class.
精彩评论