How to retrieve mapping table name for an entity in JPA at runtime?

Multi tool use


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:
Table
entityClass.getAnnotation(Table.class).name()
But what about if no Table
annotation is present?
Table
Hibernate provides this information via the Configuration
class:
Configuration
configuration.getClassMapping(entityClass.getSimpleName()).getTable().getName()
Is there something similar in JPA?
5 Answers
5
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
I wanted to avoid implementing the algorithm again. And I wanted to avoid parsing the XML mapping file, too. But I already thought, there would be no way to ask the JPA implementation for the real table names. Thanks a lot.
– marabol
Mar 1 '10 at 9:14
You can override the name using the orm.xml file so programatically re-doing the algorithm also needs to read in the correct orm file.
– Καrτhικ
Apr 18 '14 at 20:17
Link is dead...
– Alex Burdusel
Aug 3 '15 at 8:24
Link is not working
– CrazyJavaLearner
Sep 27 '16 at 9:09
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;
}
Don't think it's a correct way, e.g. what the method would return for the entity with name SomeComplexName?
– skwisgaar
Jan 11 at 11:08
@skwisgaar
SOMECOMPLEXNAME
in case there is no @Table
annotation on the entity. Otherwise the name
specified via the @Table
annotation.– Daniel Szalay
Jan 11 at 13:42
SOMECOMPLEXNAME
@Table
name
@Table
afaik default behavior is to map camelcased entities to snakecased tables (e.g. SomeComplexName -> some_complex_name). I might be wrong though :)
– skwisgaar
Jan 11 at 14:02
@skwisgaar I just tried it with Hibernate, the entity name got uppercased
– Daniel Szalay
Jan 11 at 15:07
yes, same for me (mean, when I ran the code sample) but my tables have snakecased names so I ended up splitting it by uppercase letter and joining with underscore:
String tableName = String.join("_", entity.getClass().getSimpleName().split("(?=\p{Upper})"));
. It's far from perfect but it's enough for my pretty simple case (I use it in tests).– skwisgaar
Jan 11 at 15:14
String tableName = String.join("_", entity.getClass().getSimpleName().split("(?=\p{Upper})"));
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.
This is more a comment.
– jogo
Feb 13 '16 at 20:07
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.");
}
}
}
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
as far as i know this is indeed not part of the standard API, so you will have to rely on the actual implementation (hibernate, toplink, ...) to get what you want
– Stefan De Boey
Feb 26 '10 at 14:40