2010-04-29 4 views
2

EDIT: Résolu, mais je ne sais pas ce qui était différent maintenant. Si quelqu'un peut expliquer ce qui s'est passé différemment, je l'apprécierais.Les changements JPA IndirectSet ne sont pas reflétés dans le frontend de Spring

La façon dont il travaille est maintenant en fusionnant seulement le parent, et non l'enfant du tout, comme ceci:

Parent parent = child.getParent(); 
parent.getChildren().add(child); 
getJpaTemplate().merge(parent); 

Maintenant, il semble fonctionner, mais je ne comprends pas pourquoi cela travailler alors que ma tentative précédente n'a pas.

tentative/question d'origine:

Je vais avoir un problème avec le printemps JPA et IndirectSets. J'ai deux entités, Parent et Enfant, définies ci-dessous. J'ai une forme de printemps dans laquelle j'essaie de créer un nouvel enfant et de le lier à un parent existant, puis de tout refléter dans la base de données et dans l'interface web. Qu'est-ce qui se passe, c'est qu'il est mis dans la base de données, mais l'interface utilisateur ne semble pas d'accord.

Les deux entités qui sont liées les unes aux autres dans une relation OneToMany comme ceci:

@Entity 
@Table(name = "parent", catalog = "myschema", uniqueConstraints = @UniqueConstraint(columnNames = "ChildLinkID")) 
public class Parent { 
    private Integer id; 
    private String childLinkID; 

    private Set<Child> children = new HashSet<Child>(0); 

    @Id 
    @GeneratedValue(strategy = IDENTITY) 
    @Column(name = "id", unique = true, nullable = false) 
    public Integer getId() { 
     return this.id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    @Column(name = "ChildLinkID", unique = true, nullable = false, length = 6) 
    public String getChildLinkID() { 
     return this.childLinkID; 
    } 

    public void setChildLinkID(String childLinkID) { 
     this.childLinkID = childLinkID; 
    } 

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent") 
    public Set<Child> getChildren() { 
     return this.children; 
    } 

    public void setChildren(Set<Child> children) { 
     this.children = children; 
    } 
} 

@Entity 
@Table(name = "child", catalog = "myschema") 
public class Child extends 
    private Integer id; 
    private Parent parent; 

    @Id 
    @GeneratedValue(strategy = IDENTITY) 
    @Column(name = "id", unique = true, nullable = false) 
    public Integer getId() { 
     return this.id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "ChildLinkID", referencedColumnName = "ChildLinkID", nullable = false) 
    public Parent getParent() { 
     return this.parent; 
    } 

    public void setParent(Parent parent) { 
     this.parent = parent; 
    } 
} 

Et bien sûr, les propriétés simples assortis sur chacun d'eux. Maintenant, le problème est que lorsque je modifie ces propriétés simples à partir de mon interface Spring, tout fonctionne parfaitement. Je peux persister de nouvelles entités de ces types et elles apparaîtront en utilisant JPATemplate pour faire une recherche sur, par exemple, tous les Parents (getJpaTemplate(). Find ("select p de Parent p")) ou sur des entités individuelles par ID ou une autre propriété.

Le problème que je rencontre est que maintenant, j'essaie de créer un nouvel enfant lié à un parent existant via un lien de la page du parent. Voici les bits importants du contrôleur (notez que je l'ai placé le foo JPA dans le contrôleur ici pour le rendre plus clair, la JpaDaoSupport réelle est en fait dans une autre classe, de façon appropriée à plusieurs niveaux):

protected Object formBackingObject(HttpServletRequest request) throws Exception { 
    String parentArg = request.getParameter("parent"); 
    int parentId = Integer.parseInt(parentArg); 
    Parent parent = getJpaTemplate().find(Parent.class, parentId); 
    Child child = new Child(); 
    child.setParent(parent); 
    NewChildCommand command = new NewChildCommand(); 
    command.setChild(child); 
    return command; 
} 

protected ModelAndView onSubmit(Object cmd) throws Exception { 
    NewChildCommand command = (NewChildCommand)cmd; 
    Child child = command.getChild(); 
    child.getParent().getChildren().add(child); 
    getJpaTemplate().merge(child); 
    return new ModelAndView(new RedirectView(getSuccessView())); 
} 

Comme je l'ai dit, Je peux parcourir le formulaire et remplir les nouvelles valeurs pour l'enfant - les détails du parent ne sont même pas affichés. Quand il revient au contrôleur, il le traverse et l'enregistre dans la base de données sous-jacente, mais l'interface ne le reflète jamais. Une fois que je redémarre l'application, tout est là et peuplé de manière appropriée.

Que puis-je faire pour résoudre ce problème? J'ai essayé d'appeler des fusions supplémentaires, j'ai essayé des rafraîchissements (ce qui a donné une exception de transaction), tout simplement en écrivant mon propre code d'accès à la base de données. Je me suis assuré que chaque classe a un equals approprié() et hashCode(), avoir un débogage JPA complet pour voir qu'il fait des appels SQL appropriés (il ne semble pas faire de nouveaux appels à la table enfant) et étagé à travers dans le débogueur (tout est dans IndirectSets, comme prévu, et entre enregistrer et afficher le parent l'objet prend une nouvelle adresse de mémoire). Quelle est ma prochaine étape?

Répondre

0

Je suis pas sûr cela a quelque chose à voir avec votre problème, mais pourquoi avez-vous une propriété childLinkID dans votre classe Parent? Cela semble vraiment bizarre, d'autant plus que vous utilisez la colonne correspondante pour la jointure. Je me demande comment les choses peuvent fonctionner avec cette cartographie et je réparerais cela. Pouvez-vous essayer sans (également supprimer le referencedColumnName, vous n'avez pas besoin de cela)? Et d'ailleurs, pourquoi ne pas définir les deux côtés du lien entre Parent et Child dans la même méthode? Cela rend le code difficile à lire et à maintenir IMO.


Vous avez modifié la question alors que je répondais et a changé la cascade Parent-Child mais cela ressemble à un travail autour de la vraie question et je ne suis pas sûr que vous ne face à d'autres problèmes. S'il vous plaît essayez de corriger votre cartographie comme je l'ai suggéré.

+0

La raison en est que dans le modèle réel à l'origine du problème, que j'ai simplifié, j'ai des données du monde réel qui doivent être utilisées en tant que propriété de la classe parente, qui est le mappage direct à l'enfant ici. En fait, il y a deux autres classes enfants que je dois implémenter, chacune renvoyant à une propriété/different/du parent. (Je n'ai pas conçu le modèle de données, pour éviter votre prochaine question/suggestion.) Pour répondre à la deuxième question, c'est parce que j'ai ajouté le lien de parent à enfant comme solution à ce problème (et en le corrigeant) . Cela a changé en code réel. – Jon

+0

J'ai également changé les entités de sorte que j'ai déplacé les annotations JPA des méthodes getXXX vers les déclarations de variables elles-mêmes, que j'ai oublié de mentionner. Cela aurait-il pu régler le problème également? – Jon

+0

@Jon 1) Je ne suis pas sûr d'avoir compris la nécessité de la propriété 'childLinkID' et je me demande comment JPA gère l'ensemble 2) * "c'est parce que j'ai ajouté le lien de parent à enfant pour résoudre ce problème" * - c'est ** requis ** avec les associations bidirectionnelles, vous devez définir les deux côtés du lien. 3) * "J'ai également changé les entités de sorte que j'ai déplacé les annotations JPA des méthodes getXXX vers les déclarations de variables elles-mêmes" * - cela ne change rien. En fait je pense toujours qu'il y a quelque chose d'ésotérique et que changer la cascade l'a fait fonctionner. –

Questions connexes