Comment magnifiquement mise à jour d'une entité JPA au Printemps de Données?
Donc, j'ai regardé les différents tutoriels sur JPA avec les Données du Printemps et de ce qui a été fait différents à de nombreuses reprises et je ne suis pas tout à fait sûr de ce que la bonne approche est de.
Supposer qu'il y est le prédécesseur de l'entité:
package stackoverflowTest.dao;
import javax.persistence.*;
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
public Customer(String name) {
this.name = name;
}
public Customer() {
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Nous avons aussi un DTO qui est extrait de la couche de service, puis transmises au contrôleur/côté client.
package stackoverflowTest.dto;
public class CustomerDto {
private long id;
private String name;
public CustomerDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Alors maintenant, supposons que le Client veut changer son nom dans l'interface web, il n'y aura quelques contrôleur de l'action, où il y aura la mise à jour de DTO avec l'ancien IDENTIFIANT et le nouveau nom.
Maintenant, je dois sauver la mise à jour de DTO à la base de données.
Malheureusement il n'existe actuellement aucun moyen de mettre à jour un client existant (à l'exception de la suppression de l'entrée dans la base de données et la création d'une nouvelle Cusomter avec une nouvelle auto-générée)
Cependant que ce n'est pas faisable (surtout en considérant une telle entité pourrait avoir des centaines de relations potentiellement) - il n'y venir 2 droit de l'avant des solutions à mon avis:
- faire un setter pour l'id du Client de la classe et ainsi de permettre le réglage de l'id et puis enregistrez le Client de l'objet via le référentiel.
ou
- d'ajouter le champ id du constructeur et chaque fois que vous voulez mettre à jour une clientèle toujours créer un nouvel objet avec l'ancien id, mais les nouvelles valeurs pour les autres champs (dans ce cas, seul le nom)
Donc ma question est si il y a une règle générale sur la manière de faire cela?
Tout peut-être ce que les inconvénients des 2 méthodes que j'explique?
si vous appelez
save()
avec le même ID et vous n'avez pas annulé, il vous donnera une ID en Double exception. Si vous avez configuré le Printemps Transactions correctement , alors à chaque fois que vous avez récupéré un client à partir de la DB et de fixer les valeurs que vous voulez, vous avez pu voir que certaines requêtes sont écrits dans les journaux. Mais encore laisse envisager sans JPA , dans vos scénarios de manière générale, comment vous pourriez mettre à jour un client en ligne avec simple sql ???? si vous n'avez pas la carte d'identité????Je vais ajouter quelques clarfications dans un moment, merci pour vos commentaires
J'ai mis à jour la question de la rendre un peu plus claire
OriginalL'auteur Lukas Makor | 2016-09-28
Vous devez vous connecter pour publier un commentaire.
Encore mieux que @ - Tancim Rahman de réponse, vous pouvez à l'aide de Spring Data JPA utiliser la méthode
T getOne(ID ID)
Est mieux parce que
getOne(ID id)
vous obtient seulement une référence (proxy) de l'objet et de ne pas chercher à partir de la DB. Sur cette référence, vous pouvez définir ce que vous voulez et sursave()
il va faire juste une instruction SQL UPDATE comme vous vous y attendez. En comparaison lorsque vous appelezfind()
comme dans @ - Tancim Rahmans réponse spring data JPA va faire un SELECT SQL physiquement récupérer l'entité à partir de la DB, qui vous n'avez pas besoin, quand vous êtes tout simplement la mise à jour.Cela permettra d'émettre une mise à jour des déclarations à l'encontre de tous les champs
update tbl set f1=v1, f2=v2, etc... where id=?
dba.stackexchange.com/q/176582/148282Jette LazyInitializationException dans mon cas de test.
Comment une fausse réponse pour avoir la "bonne réponse" ensemble? vous avez le champ id et la destination columen+valeur? Pourquoi ne pas émettre une mise à jour?
OriginalL'auteur Robert Niestroj
Simple JPA mise à jour..
La question est à propos du Printemps de Données. Votre réponse n'aide pas vraiment.
OriginalL'auteur Esty
Ce n'est plus un objet initialzation question plus d'une jpa question, les deux méthodes de travail et vous pouvez avoir les deux en même temps , d'habitude, si le membre de données de la valeur est prêt avant l'instanciation vous utilisez les paramètres du constructeur, si cette valeur peut être mis à jour après l'instanciation, vous devriez avoir un setter.
Hibernate est un ensemble d'API qui vous permet de travailler avec java modèles au lieu de sql, vous devez avoir vos modèles de prêt de sorte que vous pouvez utiliser ces API
Oui je sais cela, mais je me demandais si il ya certains inconvénients à l'une ou l'autre approche, ou peut-être même quelques pièges cachés.
Principalement la différence entre l'utilisation des incubateurs ou des constructeurs comme je l'ai mentionné , mais vous pouvez effectuer une recherche pour plus de détails, les réponses concernant ce
OriginalL'auteur Amer Qarabsa
Si vous avez besoin de travailler avec des Otd plutôt que les entités qui sont directement ensuite, vous devez récupérer le existant instance de Client et la carte de mise à jour les champs de la DTO.
juste une question: vous diriez que la surcharge de faire une autre requête à l'encontre de la DB est négligeable en général?
OriginalL'auteur Alan Hay
Au Printemps de Données, il vous suffit de définir une requête de mise à jour si vous avez l'ID
Certaines solutions de demander d'utiliser les données du Printemps et ne JPA oldschool (même une perte de mises à jour) à la place.
@Modifying
annotationEst-ce que votre appel de service portent le @Transactional Annotation?
oui :/ en fin de compte, j'ai vu que la validation est effectuée correctement, mais Hibernate a un cache de session qui est actualisé lors de l'enregistrement/suppression. Mais ici, il n'est pas actualisé et je peux clairement voir avec les journaux de débogage de l'obtenir entité de cache de session
Le premier niveau de cache est vidé validation et de toutes les modifications sont appliquées sur la base de données dans le conteneur de la transaction, si une entité est interrogé, dont les modifications n'ont pas été synchronisés avec la db encore. Êtes-vous au courant de cela? Peut être une bonne source d'effets secondaires.
Peut-être que vous avez touché une frange de la situation. Normalement, hibernate détecte cette "sous le capot", depuis Hibernate va suivre plus de toutes les entités dans le premier niveau de cache. Si vous allez mettre à jour une entité, il ne sera pas rincé jusqu'à ce que a) la transaction est supérieure ou b) l'entité est interrogé. Êtes-vous en mesure d'isoler ce comportement dans un test? Ensuite, vous pouvez le remettre à la source de Données de la communauté et demander de l'aide. Oh, et ne vous Demande de réaliser l' @EnableJpaRepositories annotation?
OriginalL'auteur gorefest
Je vois partout hé, je ne peut pas mettre à jour l'enregistrement de même avec jpa. il n'est pas pris en charge. je vais vous dire une chose que si vous prenez la variable cachée dans le code html et le lier à l'enregistrement existant id de domaine et puis quand vous validez le formulaire et le faire enregistrer par cet id, alors il suffit d'enregistrer posté objet d'enregistrement , et il permet d'économiser de l'enregistrement existant.
donc, la clé est de prendre de l'enregistrement existant id dans le champ caché
<form autocomplete="off" action="#" th:action="@{/site/fse}" th:objet="${site}" method="post" class="form-horizontal" role="formulaire"><div class="form-group"> <div class="col-sm-9"> <button type="submit" class="btn btn-primary btn-block">s'Inscrire</button> </div> </div> <input type="hidden" th:champ="*{id}" ></form>
dans le contrôleur: @RequestMapping(valeur="/site/fse", method = RequestMethod.POST) public ModelAndView updateSiteInformation(@Valide Site site){ log.info (le"site id est===>"+site.getId()); ModelAndView modelAndView = new ModelAndView(); Site siteExists = siteService.findSiteById(site.getId()); if (siteExists == null) { throw new RuntimeException("URL non Valide."); }else { siteRepository.enregistrer(site); modelAndView.addObject("site", site); sendEnrollmentCompletionEmail(site); modelAndView.setViewName("/site/siteenrollment"); } return modelAndView; }
Je considère ceci comme une tentative de détourner ce fil
OriginalL'auteur Ajay Kumar