【问题标题】:How to get Column names of JPA entity如何获取 JPA 实体的列名
【发布时间】:2018-03-02 07:39:46
【问题描述】:

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

public interface Entity extends Serializable {
// some methods

}

我的 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

}

我的删除方法接受一个实体。

@Override
public void delete(Entity baseEntity) {

   em.remove(baseEntity); //em is entityManager
}

每当调用 delete 方法时,我想要在我的 delete 方法中做三件事:

1) MyEntity 类型为 SecureString 的字段

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

3)id字段的值

注意当delete()方法被调用时,我们不知道它是针对哪个实体调用的,可能是针对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();
    }
}

但这只有在字段有 @Column 注释时才有效。它也没有得到我需要的其他两件事。有什么想法吗?

【问题讨论】:

  • Column name of that particular field in DB (The field may or may not have '@Column' annotation).. 您是在创建数据库表还是允许 Hibernate 创建它们?如果 hibernate 正在创建并且您没有提及“@Column”,则变量名将作为列名的默认值。
  • @KaustubhKallianpur 我允许休眠创建数据库表。有些字段有“@Column”注释,有些则没有。我同意你最后的说法。我需要有一个条件来检查特定字段是否用“@Column”注释,并且应该根据该列名获取。
  • Hibernate 获取整行和该行的所有列,并将其存储到相应的实体中。您可以使用实体中提供的 Getter 方法来获取这些变量的值。
  • 以及如何将Entity接口引用转换为MyEntity类(因为我不知道该实例是MyEntity的,所以我不能执行直接转换。它可以是MyEntity1,MyEntity2等等。)?获得对象后,我仍然需要确定 SecureString 类型上的哪些属性以及获取它的值,我该如何实现呢?你能提出一个答案吗?
  • (因为我不知道该实例属于 MyEntity。)您的意思是您不知道要获取哪一行?

标签: java hibernate jpa jakarta-ee reflection


【解决方案1】:

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

@Autowired
private EntityManagerFactory entityManagerFactory;

其次,您必须为您的班级检索AbstractEntityPersister

    SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
    AbstractEntityPersister persister = ((AbstractEntityPersister)sessionFactory.getClassMetadata(baseEntity.getClass()));

第三,您的代码几乎完成了。您只需要处理这两种情况 - 使用和不使用 @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];
            }
        }
    }
}

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

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

【讨论】:

  • sessionFactory.getClassMetadata 已弃用,建议使用EntityManagerFactory.getMetamodel()。你知道我们如何使用它并检索AbstractEntityPersister吗?
  • 我找到了:((AbstractEntityPersister)((MetamodelImplementor) entityManager.getEntityManagerFactory().unwrap( SessionFactory.class).getMetamodel()).entityPersister(baseEntity.getClass()))
  • 无论如何,您的解决方案存在规范问题! getFields 方法只返回公共字段,通常 JPA 实体中的列是 private!我们必须改用getDeclaredFields
猜你喜欢
  • 2015-12-30
  • 2020-10-16
  • 2011-03-20
  • 1970-01-01
  • 2011-06-07
  • 2020-09-12
  • 2014-11-11
  • 1970-01-01
  • 2016-08-24
相关资源
最近更新 更多