web-dev-qa-db-fra.com

Comment obtenir les noms de colonne de l'entité JPA

Toutes mes classes d'entités JPA implémentent une interface appelée Entity qui est définie comme ceci:

public interface Entity extends Serializable {
// some methods

}

Certains des champs de mon entité JPA ont une annotation @Column Au-dessus d'eux et d'autres pas. MyEntity classe est définie comme ci-dessous:

@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

}

Ma méthode de suppression accepte une entité.

@Override
public void delete(Entity baseEntity) {

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

Chaque fois que la méthode delete est invoquée, je veux trois choses dans ma méthode delete:

1) Champs de MyEntity de type SecureString

2) Nom de colonne de ce champ particulier dans la base de données (le champ peut ou non avoir l'annotation @Column)

3) La valeur du champ id

Notez que lorsque la méthode delete() est invoquée, nous ne savons pas pour quelle entité elle est invoquée, cela peut être pour MyEntity1, MyEntity2 Etc.

J'ai essayé de faire quelque chose comme ci-dessous:

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();
    }
}

Mais cela ne fonctionnera que si le champ a une annotation @Column. De plus, cela ne m'apporte pas deux autres choses dont j'ai besoin. Des idées?

7
Aman

Hibernate peut utiliser différentes stratégies de dénomination pour mapper les noms de propriété, qui sont définis implicitement (sans @Column (name = "...")). Pour avoir un nom "physique", vous devez plonger dans les internes d'Hibernate. Tout d'abord, vous devez câbler un EntityManagerFactory à votre service.

@Autowired
private EntityManagerFactory entityManagerFactory;

Deuxièmement, vous devez récupérer un AbstractEntityPersister pour votre classe

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

Troisièmement, vous y êtes presque avec votre code. Il vous suffit de gérer les deux cas - avec et sans annotation @Column. Essaye ça:

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];
            }
        }
    }
}

Notez que getPropertyColumnNames() récupère uniquement les champs 'propriété', qui ne font pas partie de la clé primaire. Pour récupérer les noms des colonnes clés, utilisez getKeyColumnNames().

Et à propos du champ id. Avez-vous vraiment besoin d'avoir tous les @ Id dans les classes enfants? Mieux vaut peut-être déplacer @Id dans la classe Entity et marquer cette classe avec l'annotation @MappedSuperclass? Ensuite, vous pouvez le récupérer simplement avec baseEntity.getId();

5
Anatoly Shamov