如何在运行时检索 JPA 中实体的映射表名称?
Posted
技术标签:
【中文标题】如何在运行时检索 JPA 中实体的映射表名称?【英文标题】:How to retrieve mapping table name for an entity in JPA at runtime? 【发布时间】:2011-01-21 11:23:10 【问题描述】:是否可以确定实体的本机表名?
如果存在Table
注释,这很容易:
entityClass.getAnnotation(Table.class).name()
但是如果没有Table
注释呢?
Hibernate 通过 Configuration
类提供此信息:
configuration.getClassMapping(entityClass.getSimpleName()).getTable().getName()
JPA 中有类似的东西吗?
【问题讨论】:
据我所知,这确实不是标准 API 的一部分,因此您将不得不依赖实际实现(hibernate、toplink、...)来获得您想要的 【参考方案1】:我的一位同事为 Hibernate 支持的 Spring Data JPA 环境找到了以下解决方案:
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.");
【讨论】:
【参考方案2】:询问底层 ORM 的元模型是最可靠的:仅查看 @Table 的存在是不够的,它不仅可以被 XML 配置(例如 orm.xml)覆盖,而且可以使用 JOINED 策略, @Table 可能在超类中。
【讨论】:
这更像是一条评论。【参考方案3】:这是我在 EclipseLink 中使用的方法(无映射文件):
/**
* 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;
【讨论】:
不要认为这是正确的方法,例如该方法将为名称为 SomeComplexName 的实体返回什么? @skwisgaarSOMECOMPLEXNAME
以防实体上没有 @Table
注释。否则,通过 @Table
注释指定的 name
。
afaik 默认行为是将驼峰实体映射到蛇形表(例如 SomeComplexName -> some_complex_name)。不过我可能错了:)
是的,对我来说也一样(意思是,当我运行代码示例时)但我的表有蛇形名称,所以我最终用大写字母分割它并用下划线连接:String tableName = String.join("_", entity.getClass().getSimpleName().split("(?=\\pUpper)"));
。它远非完美,但对于我非常简单的案例来说已经足够了(我在测试中使用它)。
如果@Table
没有名称和一些可配置的命名策略将实体名称转换为数据库表名称,这将不起作用。【参考方案4】:
如果您使用@Table 注释,则没有问题,如您所示。如果不使用该注解,则表名与类名相同(JPA 默认)。
如果你使用映射文件,乐趣就开始了,你需要解析它并检索表名——这不是很困难,但需要一些工作。如果您担心性能问题,那么您可以解析一次映射文件并缓存所有表名。
【讨论】:
【参考方案5】:如果没有表注释(也没有 ORM.xml),那么在 JPA 中,表名是根据类名形成的(参见 JPA 规范)。因此,您究竟为什么需要访问器方法?
见http://www.datanucleus.org/products/accessplatform_2_0/jpa/orm/datastore_identifiers.html
【讨论】:
我想避免再次实现该算法。我也想避免解析 XML 映射文件。但我已经想到,没有办法向 JPA 实现询问真实的表名。非常感谢。 您可以使用 orm.xml 文件覆盖名称,因此以编程方式重新执行算法也需要读取正确的 orm 文件。以上是关于如何在运行时检索 JPA 中实体的映射表名称?的主要内容,如果未能解决你的问题,请参考以下文章