Lazy One-To-One Spring JPA并构建“动态”JSON
我正在使用Spring Boot开发一个相对较大的项目,一般来说我对它很满意,但是我遇到了一些问题,在我看来应该不是问题。
-
首先,一对一的关系。 令人沮丧的是它不能正常工作(至少在我看来)。
我有两个实体,例如
User
和UserProfile
。 他们有一对一的关系,但大多数时候我只需要User
数据,但它取而代之(无论我尝试什么,哦,男孩,我在5页Google的每篇post上尝试了世界建议)。所以我的第一个问题是,有没有办法能够在JPA和Spring中懒惰地获取一对一的关系? (因为大多数post都超过2 – 3年)。
-
我遇到的另一个问题是以“动态”方式构建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以将其存储在代理中。 因此,无论如何它必须转到相关的表。
解决方案:
- 字节代码检测 。 虽然没有广泛采用的方法。
- 使用一对多并将空列表处理为
null
,否则使用list.get(0)
。 您当然可以将其封装在实体类中(getter返回列表中唯一的元素或null
)。 缺点是您必须将其视为JPQL查询中的集合。 - 使用
@PrimaryKeyJoinColumn
而不是外键。 如果关联不是可选的(optional = false
),则JPA提供程序知道存在具有相同PK的关联子级,因此它将仅存储父级的PK作为代理中子级的ID。 显然,您不能为两个实体使用两个独立的id生成器,否则PK可能不同。 如果它符合您的要求,这是最好的方法。 - 也可以在父表中添加外键(使数据库中的关系也是双向的)。 缺点是你现在基本上有两个独立的关联,你必须维护。 此外,还有更新两个表而不是一个表的性能成本(并且外键必须可以为空)。
-
将父实体映射到将父表与子表连接的数据库视图,并包含所有父列和子表的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这样的实体分解为多个类,同时将数据保存在数据库中,因此只能使用一个查询来获取它。