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