J'ai ces deux entités simples Something
et Property
. L'entité Something
a une relation plusieurs-à-un avec Property
, donc lorsque je crée une nouvelle ligne Something
, j'affecte un Property
existant.
Quelque chose:
@Entity
@Table(name = "something")
public class Something implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "owner")
private String owner;
@ManyToOne
private Property property;
// getters and setters
@Override
public String toString() {
return "Something{" +
"id=" + getId() +
", name='" + getName() + "'" +
", owner='" + getOwner() + "'" +
", property=" + getProperty() +
"}";
}
Propriété:
@Entity
@Table(name = "property")
public class Property implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "shape")
private String shape;
@Column(name = "color")
private String color;
@Column(name = "dimension")
private Integer dimension;
// getters and setters
@Override
public String toString() {
return "Property{" +
"id=" + getId() +
", shape='" + getShape() + "'" +
", color='" + getColor() + "'" +
", dimension='" + getDimension() + "'" +
"}";
}
}
Voici le SomethingRepository
(Spring):
@SuppressWarnings("unused")
@Repository
public interface SomethingRepository extends JpaRepository<Something,Long> {
}
A travers un REST et un JSON, je veux créer un nouveau Something
:
@RestController
@RequestMapping("/api")
public class SomethingResource {
private final SomethingRepository somethingRepository;
public SomethingResource(SomethingRepository somethingRepository) {
this.somethingRepository = somethingRepository;
}
@PostMapping("/somethings")
public Something createSomething(@RequestBody Something something) throws URISyntaxException {
Something result = somethingRepository.save(something);
return result;
}
}
Il s'agit du JSON en entrée (le property
id
1 est une ligne existante dans la base de données):
{
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1
}
}
Le problème est: après la méthode .save(something)
, la variable result
contient l'entité persistante, mais sans les champs du champ property
, validée (ce sont null
):
Sortie JSON:
{
"id": 1,
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1,
"shape": null,
"color": null,
"dimension": null
}
}
Je m'attends à ce qu'ils soient validés/retournés après l'opération de sauvegarde.
Pour contourner cela, je dois injecter/déclarer le EntityManager
dans le contrôleur REST, et appeler la méthode EntityManager.refresh(something)
(ou je dois appeler un .findOne(something.getId())
méthode pour avoir l'entité persistante complète):
@RestController
@RequestMapping("/api")
@Transactional
public class SomethingResource {
private final SomethingRepository somethingRepository;
private final EntityManager em;
public SomethingResource(SomethingRepository somethingRepository, EntityManager em) {
this.somethingRepository = somethingRepository;
this.em = em;
}
@PostMapping("/somethings")
public Something createSomething(@RequestBody Something something) throws URISyntaxException {
Something result = somethingRepository.save(something);
em.refresh(result);
return result;
}
}
Avec cette solution de contournement, j'ai l'entith enregistré attendu (avec un JSON correct):
{
"id": 4,
"name": "MyName",
"owner": "MySelf",
"property": {
"id": 1,
"shape": "Rectangle",
"color": "Red",
"dimension": 50
}
}
Existe-t-il une méthode/annotation automatique, avec JPA ou Spring ou Hibernate, afin d'avoir l'entité persistante "complète"?
Je voudrais éviter de déclarer l'EntityManager dans chaque REST ou classe Service, ou je veux éviter d'appeler la méthode .findOne (Long) chaque fois que je veux la nouvelle entité persistante actualisée.
Merci beaucoup, Andrea
Dans Spring Boot JpaRepository:
Si notre requête de modification change les entités contenues dans le contexte de persistance, ce contexte devient obsolète.
Afin de récupérer les entités de la base de données avec le dernier enregistrement.
Utilisez @Modifying (clearAutomatically = true)
L'annotation @Modifying a l'attribut clearAutomatically qui définit si elle doit effacer le contexte de persistance sous-jacent après l'exécution de la requête de modification.
Exemple:
@Modifying(clearAutomatically = true)
@Query("UPDATE NetworkEntity n SET n.network_status = :network_status WHERE n.network_id = :network_id")
int expireNetwork(@Param("network_id") Integer network_id, @Param("network_status") String network_status);