Lazy One-To-One Spring JPA并构建“动态”JSON

我正在使用Spring Boot开发一个相对较大的项目,一般来说我对它很满意,但是我遇到了一些问题,在我看来应该不是问题。

  1. 首先,一对一的关系。 令人沮丧的是它不能正常工作(至少在我看来)。

    我有两个实体,例如UserUserProfile 。 他们有一对一的关系,但大多数时候我只需要User数据,但它取而代之(无论我尝试什么,哦,男孩,我在5页Google的每篇post上尝试了世界建议)。

    所以我的第一个问题是,有没有办法能够在JPA和Spring中懒惰地获取一对一的关系? (因为大多数post都超过2 – 3年)。

  2. 我遇到的另一个问题是以“动态”方式构建JSON响应。 我使用Rails做了一些事情,并且对JBuilder甚至to_json非常满意,这让我能够根据控制器和我目前的需求构建json响应。

    在Spring中,我看到了以下解决方案:

    • Jackson @JsonView (它不能完全解决我的问题,因为响应不是静态的,并且属性不能分配给多个视图(据我理解的概念));
    • 设置为null我不想要的响应属性(使用它,但我太丑了,看起来像一个错误的演练);
    • 或者构建HashMap就像我在Rails上构建.json.jbuilder一样(但这会.json.jbuilder我的表现,因为有时它会有很多关系来构建json,而且这看起来像是一个丑陋的演练)。

我正在寻找某人的某些指示,有朝一日可能会遇到其中一个问题,因为它让我无法解决问题,而在我看来这不应该是这么难。

编辑1

已经尝试在@OneToOne注释上添加optional = false来解决@snovelli建议的OneToOne关系的Eager负载。 例:

 @OneToOne(optional=false, fetch = FetchType.LAZY) public UserProfile getUserProfile(){ ... } 

如果连接列不在映射一对一关联中的父级的表中,则该关联不能是惰性的 。 原因是JPA提供程序无法确定是否创建代理,以便它可以在以后访问时加载对象,或保留null值。

即使关联不是可选的,JPA提供者也必须确定关联实体实例的id以将其存储在代理中。 因此,无论如何它必须转到相关的表。

解决方案:

  1. 字节代码检测 。 虽然没有广泛采用的方法。
  2. 使用一对多并将空列表处理为null ,否则使用list.get(0) 。 您当然可以将其封装在实体类中(getter返回列表中唯一的元素或null )。 缺点是您必须将其视为JPQL查询中的集合。
  3. 使用@PrimaryKeyJoinColumn而不是外键。 如果关联不是可选的( optional = false ),则JPA提供程序知道存在具有相同PK的关联子级,因此它将仅存储父级的PK作为代理中子级的ID。 显然,您不能为两个实体使用两个独立的id生成器,否则PK可能不同。 如果它符合您的要求,这是最好的方法。
  4. 也可以在父表中添加外键(使数据库中的关系也是双向的)。 缺点是你现在基本上有两个独立的关联,你必须维护。 此外,还有更新两个表而不是一个表的性能成本(并且外键必须可以为空)。
  5. 将父实体映射到将父表与子表连接的数据库视图,并包含所有父列和子表的id:

     @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "", insertable = false, updatable = false) private Child child; 

关于’动态’JSON:使用DTO 。

这样做的好处是可以将要序列化的对象定制为使用生成的JSON的客户端的确切需求。 此外,域模型(Hibernate实体)与JSON(de)序列化逻辑分离,允许两者独立发展。

关于@OneToOne :您是否更担心数据量或针对数据库的多次查询?

在前一种情况下(如果使用Spring Roo时可能),您可以尝试使用@ManyToOne关系建模(一对一是多对一的特殊情况,不是这样)。

在后一种情况下,您可以使用@Embeddable将像User这样的实体分解为多个类,同时将数据保存在数据库中,因此只能使用一个查询来获取它。