Spring Data JPA, un framework pour la persistance des données dans Spring, vous permet de définir des relations entre deux classes Entity. À ce moment, vous pouvez définir une référence à l'autre objet dans la classe de l'autre, qui est appelée une référence mutuelle. Il y avait plusieurs points bloqués lors de l'utilisation de références mutuelles, je vais donc les résumer. La version que j'ai utilisée est Spring Data JPA 1.10.6 et je crée un projet à l'aide de Spring Boot 1.4.3.
Les relations entre les classes Entity peuvent être spécifiées à l'aide d'annotations telles que "@OneToOne", "@OneToMany", "@ManyToOne" et "@ManyToMany". Les relations exprimées par "@OneToMany" et "@ManyToOne" semblent être les mêmes, mais vous pouvez spécifier comment la classe Entity de l'autre côté est liée à la classe Entity.
Plus précisément, regardons la relation entre les données des employés et de l'entreprise. Le diagramme ER est le suivant.
Si cela est transformé en une classe d'entité de référence mutuelle, ce sera comme suit.
Company.java
@Entity
class Company {
@Id
private long id;
private String name;
@OneToMany //Plusieurs à 1
List<Employee> employees;
/*Abréviation d'accesseur*/
}
Employee.java
@Entity
class Employee {
@Id
private long id;
private String name;
@ManyToOne //Beaucoup
Company company;
/*Abréviation d'accesseur*/
}
Puisqu'il s'agit d'une référence mutuelle, l'entreprise dispose d'une liste de classes d'employés, qui ne figure pas sur le diagramme ER. L'ID de société côté employé devient une référence à la classe de société lors de sa classification.
Comme indiqué dans le diagramme ER, l'ID de l'entreprise (référence à la classe de l'entreprise) dans l'entité employé est traité comme une clé externe. En général SGBDR, si une clé externe est définie, l'élément cible doit exister en premier. Il en va de même pour JPA, où l'objet société doit d'abord être enregistré avant que l'objet employé puisse être enregistré dans le DB.
@Autowired
EmployeeRepository empRepository;
@Autowired
CompanyRepository coRepository;
@PostConstruct
public init() {
/*Enregistrement de la société*/
Company co = new Company();
co.setName("Société A");
coRepository.saveAndFlush(co);
/*Inscription des employés*/
Employee emp = new Employee();
emp.setName("Sato");
emp.setCompany(co); //Paramètres d'entreprise enregistrés requis
empRepository.saveAndFlush(emp);
}
Par le processus ci-dessus, nous avons pu enregistrer la société «co» et l'employé «emp» dans la base de données. Cependant, lorsque je retire «co» du «coRepository» et que je regarde le contenu des «employés», les données de M. Sato ne sont pas stockées. En fait, même si vous créez une entité de référence mutuelle, les informations de l'objet correspondant ne sont pas automatiquement stockées dans la structure de données correspondante. Par conséquent, pour faire référence à l'objet de M. Sato à partir de l'objet de la société A, il est nécessaire de définir explicitement les données et de les enregistrer dans la base de données.
public init() {
/*Enregistrement de la société*/
/*Inscription des employés*/
co.setEmployees(Arrays.asList(emp));
coRepository.saveAndFlush(co);
}
Pour être enregistré, l'objet employé cible doit d'abord être enregistré dans le DB. La raison pour laquelle cela se produit est que les références d'employé à entreprise ont des données dans la table des employés, tandis que les références d'entreprise à employé gèrent les relations de référence dans une table séparée. Parce que c'est. En d'autres termes, les deux entités de référence mutuelle sont gérées par les trois tableaux suivants.
Cependant, cette méthode gère séparément les informations «entreprise pour salariés» et «salarié pour entreprise».
Par conséquent, utilisez l'option mappedBy
fournie par @OneToMany.
Employee.java
/*réduction*/
@OneToMany(mappedBy="company") //Plusieurs à 1
List<Employee> employees;
/*réduction*/
La valeur spécifiée pour mappedBy sera le "nom de variable de champ correspondant (avec @ManyToOne)".
Compnay.java
/*réduction*/
@ManyToOne //Beaucoup
Company company;
/*réduction*/
Cela empêchera la création de la table de gestion des références. S'il n'y a pas de table de gestion de référence, le contenu des «employés» est automatiquement créé à partir de la table des employés. Cela élimine le besoin de définir une liste de «Employés» avec la méthode «setEmployees» de «Company».
Les références mutuelles sont des références circulaires car elles ont toutes deux des références d'objet l'une à l'autre. Lorsque vous traitez avec des objets de référence circulaires, vous devez être conscient de la possibilité d'étendre la référence indéfiniment. Lors de la conversion en un objet JavaScript avec RestController ou Thyemelaf of Spring, le processus de conversion de chaque objet au format json est effectué. Cependant, si vous utilisez un objet qui a des références circulaires, il se développera indéfiniment. Par exemple, si vous développez l'objet Employé:
{"id":1, "name":"Sato", "company":{"id":1, "name":"Société A", "employees":[{"id":1, "name":"Sato", "company":{…}}]}}
Cela entraînera finalement une StackOverflowError et le programme plantera.
Une façon d'éviter une expansion infinie est, bien sûr, d'arrêter les références circulaires (références mutuelles).
Vous pouvez éviter une expansion infinie en supprimant le champ company
de la classe Employee ou le champ ʻemployeesde la classe Company pour éliminer les références circulaires. Cependant, comme les références mutuelles sont pratiques, il y a des moments où vous souhaitez éviter une expansion infinie tout en laissant des références mutuelles. Pour ce faire, percez un trou dans le processus d'expansion des objets de Spring. Le processus d'expansion d'objet étend le getter cible, c'est-à-dire la méthode nommée
get ○○. Par conséquent, vous pouvez éviter une expansion infinie en renommant les getters des objets référencés. Par exemple, renommez la méthode
getEmployee de la classe Company en ʻacquireEmployee
.
Ensuite, la méthode ʻacquireEmployee` n'est pas incluse dans la cible d'expansion de jsonization, vous pouvez donc éviter une expansion infinie.
Company.java
@Entity
class Company {
/*réduction*/
/*Changer en privé*/
private getEmployees(){
return employees;
}
/*Appel getter*/
public acquireEmpployees(){
return getEmployees();
}
}
Dans l'exemple ci-dessus, au lieu de simplement le renommer, j'ai rendu le getter d'origine privé et l'ai appelé depuis le public ʻacquireEmployees`. Même les méthodes avec le préfixe get ne développent pas les méthodes privées, évitant ainsi les références circulaires.
{"id":1, "name":"Sato", "company":[{"id":1, "name":"Société A"}]}
Vous ne pourrez pas voir les employés de l'entreprise dans RestController ou les objets JavaScript. Cependant, il peut être utilisé en Java et Thymeleaf en appelant la méthode ʻacquireEmployees`.
thymeleaf
<ul>
<li th:each="emp: ${company.acquireEmployees()}" th:text="${emp}"></li>
</ul>
Comme mentionné ci-dessus, le processus de jsonisation appelle une méthode qui est publique et a get comme préfixe pour effectuer l'expansion.
Inversement, si la méthode est publique et a get comme préfixe, elle sera incluse dans la propriété de l'objet au moment de la jsonisation même si elle n'a pas les informations renvoyées par elle dans le champ.
Par exemple, si vous souhaitez que la propriété inclue le nombre d'employés dans l'entreprise, ajoutez la méthode getEmployeeNumber
.
Company.java
@Entity
class Company {
/*réduction*/
private getEmployees(){
return employees;
}
public getEmployeeNumber(){
return getEmployees().size();
}
}
{"id":1, "name":"Sato", "company":[{"id":1, "name":"Société A", "employeeNumber":1}]}
En utilisant cela, même si json ne peut pas inclure un objet qui provoque une référence circulaire, il est possible de renvoyer des valeurs représentatives de données. Vous pouvez également renvoyer complètement chaque élément de données en définissant une classe interne qui exclut les références (bien que ce soit fastidieux).
StackOverFlow lors de l'appel de l'entité référencée mutuellement par @OneToMany en JavaScript à l'aide de Thymeleaf Relations JPA: @OneToMany et @ManyToOne Premier JPA - Simple et facile à utiliser, découvrez les bases de la fonction de persistance des données de Java EE
Recommended Posts