2017-01-31 1 views
12

J'ai une entité qui possède une autre entité:Comment renvoyez-vous un sous-ensemble d'une entité JPA appartenant à une autre entité?

//psuedocode  
public class ClassA{ 
    private String name; 

    @OneToOne 
    private ClassB classb; 
} 

public class ClassB{ 
    private String thing1; 
    private String thing2; 
    private String thing3; 
} 

Quand je récupérer des objets ClassA, je ne veux pas voir ClassB.thing3, mais je ne veux voir Thing1 chose et 2:

{ 
"name":"classa", 
"classb":{ 
     "thing1":"hi", 
     "thing2":"there" 
     } 
} 

Mais si je fais une recherche ClassB Je veux tout voir:

{"thing1":"hi", 
"thing2":"there", 
"thing3":"joseph"} 

donc je ne peux pas simplement mettre l'annotation sur Thing3 ignorer, parce que je vais l'ignorer sur le seco ND aller chercher. J'ai essayé un Converter<ClassB>, mais cela me force à implémenter toString() et fromString() pour le JSON, qui meurt en convertissant l'objet JSON en Java (le convertisseur attend une chaîne, mais obtient l'objet à la place).

Je veux éviter de construire/analyser l'objet JSON moi-même si possible pour laisser mon fournisseur json faire le travail, si possible. Je suis sur Johnzon.

+1

Quel est votre fournisseur json? Jackson prend en charge les vues Json qui peuvent faire ce que vous voulez, mais ce n'est pas standard. Ex: http://www.baeldung.com/jackson-json-view-annotation – Gimby

Répondre

1

Ceci est possible, vous devez utiliser @NamedEntityGraph,

Cela devrait aider, http://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/

+0

Je pense que pour que cela soit accepté comme réponse, vous devriez au moins décrire la mise en œuvre pour le cas OP, pas seulement pointer vers un tutoriel générique . – Deltharis

+0

merci, va faire! était pressé @Deltharis – zillani

+0

Je ne sais pas si @ NamedEntityGraph est la voie à suivre ici parce que [JPA 2.1] (http://download.oracle.com/otndocs/jcp/persistence-2_1-fr-eval-spec/index. html) Spec permet au fournisseur d'extraire autant de données qu'il le souhaite, il n'y a donc aucune garantie sur ClassB.thing3 ne sera pas chargé, simplement parce qu'il ne figure pas dans le graphique d'entité: _Le fournisseur de persistance est autorisé à extraire un état d'entité supplémentaire au-delà de ce qui est spécifié par un graphe de récupération ou un graphe de charge. Il est cependant nécessaire que le fournisseur de persistance récupère tout l'état spécifié par le graphique de chargement ou de chargement. – tom

1

Quelque chose comme cela devrait être possible en questionnant en utilisant SELECT NOUVEAU, mais vous allez avoir besoin de nouvelles classes pour cela ... et ne passera pas vos entités directement à JSON.

nouvelles classes: (pseudocode)

class ResultB { 
    String thing1; 
    String thing2; 

    public ResultB(ClassB classB) { 
     this.thing1 = classB.thing1; 
     this.thing2 = classB.thing2; 
    } 
} 

class ResultA { 
    String name; 
    ResultB resultB; 

    public ResultA(ClassA classA) { 
     this.name=classA.name; 
     this.resultB=new ResultB(classA); 
    } 
} 

Requête:

select new ResultA(a) from ClassA a fetch join a.classB; 

Ensuite, vous pouvez passer resulta au lieu de ClassA à JSON.

PS: Comme mentionné dans le commentaire ci-dessus, je ne pense pas NamedEntityGraphs sont la voie à suivre ici

+0

Cela pourrait être une solution, mais au lieu de transmettre ResultA à mon fournisseur Json, je serais tenté de le reconvertir en ClassA et ClassB afin que l'interface de l'interface de mon équipe reste la même. Cela a l'avantage de ne pas avoir à dépenser des ressources pour aller chercher des champs inutiles, mais il y a tout ce que je vais devoir faire dans mon équipe car cela va à l'encontre de notre standard actuel d'utilisation les entités comme nos classes de transfert et d'accès de données. – GuitarStrum

+0

Hmm, oui, vous pouvez le reconvertir dans les classes d'origine, mais vous devriez faire attention à ce que ces classes ne soient pas persistet "telles quelles" lorsqu'elles sont retournées car vous pourriez effacer des champs (nullable) (ou produire des exceptions si les champs ne sont pas valables). – tom

1

je toujours chercher toutes les données de la base de données et de laisser le filtrage à faire par le fournisseur de JSON si vous voulez le sérialiser quand même. Si vous utilisez Jackson, vous pouvez simplement ajouter des vues à vos champs:

public class ClassA { 

    @JsonView(Views.AlwaysInclude.class) 
    private String name; 

    @JsonView(Views.AlwaysInclude.class) 
    @OneToOne 
    private ClassB classb; 
} 

public class ClassB { 
    @JsonView(Views.AlwaysInclude.class) 
    private String thing1; 

    @JsonView(Views.AlwaysInclude.class) 
    private String thing2; 

    private String thing3; 
} 

public class Views { 
    public static class AlwaysInclude { 
    } 
} 

plus tard lorsque vous sérialiser votre objet que vous avez juste besoin d'utiliser votre point de vue:

String result = mapper 
    .writerWithView(Views.AlwaysInclude.class) 
    .writeValueAsString(new ClassA()); 

Lorsque vous voulez sérialiser seulement ClassB vous ne devrait pas utiliser de vues.

String result = mapper.writeValueAsString(new ClassB()); 
+0

Nous n'utilisons pas Jackson mais merci. Pour le "je chercherais toujours toutes les données de la base de données et laisserais le filtrage être fait par le fournisseur JSON", je peux aller dans une route similaire et juste effacer les champs dont je n'ai pas besoin de ClassB quand je récupère ClassA. L'inconvénient de cette approche est que je continue de dépenser des ressources pour aller chercher des données dont je n'ai pas besoin, mais d'un autre côté je peux laisser mon fournisseur construire le bon JSON pour moi. – GuitarStrum