您如何发回由另一个实体拥有的 JPA 实体的子集?

Posted

技术标签:

【中文标题】您如何发回由另一个实体拥有的 JPA 实体的子集?【英文标题】:How do you send back a subset of a JPA entity that is owned by another entity? 【发布时间】:2017-06-17 13:48:02 【问题描述】:

我有一个拥有另一个实体的实体:

//psuedocode    
public class ClassA
   private String name;

   @OneToOne
   private ClassB classb;


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

当我检索 ClassA 对象时,我不想看到 ClassB.thing3,但我确实想看到 thing1 和 thing 2:


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

但如果我查询 ClassB,我想查看所有内容:

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

所以我不能只在 thing3 上放置一个忽略注释,因为那样我会在第二次获取时忽略它。我尝试了Converter<ClassB>,但这迫使我为 JSON 实现 toString()fromString(),这在将 JSON 对象转换为 Java 端时会死掉(转换器需要一个字符串,但改为获取对象)。

如果可能的话,我想避免自己构建/解析 JSON 对象,让我的 json 提供程序完成工作。我在 Johnzon。

【问题讨论】:

你的 json 提供者是什么? Jackson 支持 Json 视图,它可以做你想做的,但它是非标准的。例如:baeldung.com/jackson-json-view-annotation 【参考方案1】:

这是可能的,你需要使用@NamedEntityGraph,

这应该会有所帮助,http://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/

【讨论】:

我认为,为了让其被接受为答案,您至少应该描述 OPs 案例的实现,而不仅仅是指向通用教程。 不确定@NamedEntityGraph 是否适合这里,因为JPA 2.1 Spec 允许提供者获取它认为合适的数据,因此不能保证 ClassB.thing3 不会被加载,仅仅因为它不在实体图中:允许持久性提供程序获取超出获取图或加载图指定的其他实体状态。但是,持久性提供程序需要获取 fetch 或 load 图指定的所有状态。 我试过了,但它在 OpenJPA 上对我没有任何作用。在 LAZY 提取时,我什么也得不到,而在 EAGER 提取时,我得到了一切。我正在修改注释,看看我是否可以让它工作。 经过几个小时的研究和尝试,我不确定它是否适用于我的情况。我找不到任何确认这可以与 OpenJPA 一起使用,而且我试图让它与它一起工作的几个小时并没有帮助它的情况。从不同的教程和诸如此类的东西来看,它或多或少看起来像我想要的,我真的希望它能够正常工作;它似乎不适用于我的设置。【参考方案2】:

这样的事情应该可以通过使用 SELECT NEW 进行查询来实现,但是您将需要一些新的类...并且不会将您的实体直接传递给 JSON。

新课程: (伪代码)

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);
   

查询:

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

然后您可以将 ResultA 而不是 ClassA 传递给 JSON。

PS:正如上面评论中提到的,我认为 NamedEntityGraphs 不是这里的路

【讨论】:

这可能是一种解决方案,但不是将 ResultA 传递给我的 Json 提供程序,我很想将其转换回 ClassA 和 ClassB,以便我团队前端的接口保持不变。这确实带来了不需要花费资源来获取不需要的字段的好处,但伴随着整个“需要特殊数据访问类”的事情,我必须在我的团队中运行,因为它违反了我们目前的使用标准实体作为我们的数据传输和访问类。 嗯,是的,您可以将其转换回原始类,但是您应该小心,这些类在返回时不会“按原样”持久化,因为您可能正在擦除(可为空) 字段(如果字段不可为空,则产生异常)。【参考方案3】:

如果你想序列化它,我总是会从数据库中获取所有数据并让 JSON 提供程序完成过滤。如果您使用 Jackson,您可以简单地将视图添加到您的字段:

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 
    

稍后当你序列化你的对象时,你只需要使用你的视图:

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

如果您只想序列化 ClassB,则不应使用视图。

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

【讨论】:

我们没有使用 Jackson,但谢谢。对于“我将始终从数据库中获取所有数据并让 JSON 提供程序完成过滤”评论,我可以采用类似的方法,并在获取 ClassA 时将 ClassB 中不需要的字段清空。这种方法的缺点是我仍在花费资源来获取我不需要的数据,但另一方面,我可以让我的提供者为我构建正确的 json。

以上是关于您如何发回由另一个实体拥有的 JPA 实体的子集?的主要内容,如果未能解决你的问题,请参考以下文章

JPA双向实体:在查询父实体时仅选择子实体的子集

是否有 JPA / JPQL 查询来搜索春季作为 JSON 传递的实体子集?

仅选择实体集合的子集

Flowable入门系列文章70 - JPA介绍

使用 JPA 连接从父实体返回子实体

如何更新CoreData中另一个实体的子实体