如何获取JPA实体的列名

Ama*_*man 5 java reflection hibernate jpa java-ee

我所有的JPA实体类都实现了一个称为Entity的接口,其定义如下:

public interface Entity extends Serializable {
// some methods

}
Run Code Online (Sandbox Code Playgroud)

我的JPA实体的某些字段@Column在其顶部有注释,而有些则没有。MyEntity类的定义如下:

@Entity
public class MyEntity implements Entity {

   @Id
   private Long id; // Assume that it is auto-generated using a sequence. 

   @Column(name="field1")
   private String field1;


   private SecureString field2; //SecureString is a custom class

   //getters and setters

}
Run Code Online (Sandbox Code Playgroud)

我的delete方法接受一个Entity。

@Override
public void delete(Entity baseEntity) {

   em.remove(baseEntity); //em is entityManager
}
Run Code Online (Sandbox Code Playgroud)

每当调用delete方法时,我都希望在delete方法内包含三件事:

1)MyEntity该类型的字段SecureString

2)DB中该特定字段的列名(该字段可能带有@Column注释,也可能没有注释)

3)id字段的值

请注意,在delete()调用该方法时,我们不知道为哪个实体调用,可能是for的MyEntity1MyEntity2等等。

我曾尝试做以下事情:

for (Field field : baseEntity.getClass().getFields()) {
    if (SecureString.class.isAssignableFrom(field.getType())) {
        // But the field doesn't have annotation @Column specified
        Column column = field.getAnnotation(Column.class);

        String columnName = column.name();
    }
}
Run Code Online (Sandbox Code Playgroud)

但这仅在字段具有@Column注释的情况下有效。同样,这并没有给我带来我需要的其他两件事。有任何想法吗?

Ana*_*mov 10

Hibernate 可以使用不同的命名策略来映射属性名称,这些名称是隐式定义的(没有@Column(name = "..."))。要获得“物理”名称,您需要深入了解 Hibernate 内部结构。首先,您必须将 an 连接EntityManagerFactory到您的服务。

@Autowired
private EntityManagerFactory entityManagerFactory;
Run Code Online (Sandbox Code Playgroud)

其次,你必须AbstractEntityPersister为你的班级检索一个

    SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
    AbstractEntityPersister persister = ((AbstractEntityPersister)sessionFactory.getClassMetadata(baseEntity.getClass()));
Run Code Online (Sandbox Code Playgroud)

第三,您的代码就快完成了。您只需要处理这两种情况 - 有和没有 @Column 注释。尝试这个:

for (Field field : baseEntity.getClass().getFields()) {
    if (SecureString.class.isAssignableFrom(field.getType())) {
        String columnName;
        if (field.isAnnotationPresent(Column.class)) {
            columnName = field.getAnnotation(Column.class).name();
        } else {
            String[] columnNames = persister.getPropertyColumnNames(field.getName());
            if (columnNames.length > 0) {
                columnName = columnNames[0];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,getPropertyColumnNames()只检索不属于主键的“属性”字段。要检索键列名称,请使用getKeyColumnNames().

而关于id领域。您真的需要在子类中拥有所有@Id 吗?也许最好将@Id 移动到Entity类并用@MappedSuperclass 注释标记这个类?然后你可以用baseEntity.getId();

  • `sessionFactory.getClassMetadata` 已弃用,建议使用 `EntityManagerFactory.getMetamodel()`。您知道我们如何使用它并检索“AbstractEntityPersister”吗? (2认同)
  • 我找到了它:`((AbstractEntityPersister)((MetamodelImplementor)entityManager.getEntityManagerFactory().unwrap(SessionFactory.class).getMetamodel()).entityPersister(baseEntity.getClass()))` (2认同)
  • 无论如何,你的解决方案有一个规范问题!“getFields”方法仅返回公共字段,并且通常 JPA 实体中的列是“私有”!我们必须使用 `getDeclaredFields` 来代替 (2认同)