简体   繁体   English

懒惰的One-To-One Spring JPA并构建“动态”JSON

[英]Lazy One-To-One Spring JPA and building “dynamic” JSON

I'm developing a relatively large project using Spring Boot, and in a general way I'm pretty happy with it, but I'm having some problems that in my mind should't be a problem. 我正在使用Spring Boot开发一个相对较大的项目,一般来说我很满意它,但是我遇到了一些问题,在我看来应该不是问题。

  1. First of all, One-To-One Relationship. 首先,一对一的关系。 It's frustrating that it doesn't work as it should (at least in my mind). 令人沮丧的是它不能正常工作(至少在我看来)。

    I have two entities, User and UserProfile , for example. 我有两个实体,例如UserUserProfile They have One-To-One relationship, but most of the time I only need the User data, but it fetches (no matter what I try, and oh boy, I tried the world suggestions on every post for 5 pages of Google). 他们有一对一的关系,但大部分时间我只需要User数据,但它取出(无论我尝试什么,哦,男孩,我在5页Google的每篇帖子上尝试了世界建议)。

    So there is my first question, is there a way to be able to lazy fetch One-To-One relationship in JPA and Spring? 所以我的第一个问题是,有没有办法能够在JPA和Spring中实现懒惰的一对一关系? (Because most of the posts are more than 2-3 years old). (因为大部分帖子都超过2 - 3年)。

  2. The other problem I have is about to build a JSON response in a "dynamic" way. 我遇到的另一个问题是以“动态”方式构建JSON响应。 I did some stuff using Rails and was very happy with JBuilder or even the to_json that gave me the ability to build the json response depending on the controller and my needs at the moment. 我使用Rails做了一些事情,并且对JBuilder甚至to_json非常满意,这让我能够根据控制器和我目前的需求构建json响应。

    In Spring I saw the following solutions: 在Spring中,我看到了以下解决方案:

    • Jackson @JsonView (which doesn't solve entirely my problem because the responses are not that static and a attribute can't be assigned to multiple views (as far as I understood the concept)); Jackson @JsonView (它不能完全解决我的问题,因为响应不是静态的,并且属性不能分配给多个视图(据我理解的概念));
    • setting to null attributes that I don't want on the response (using this, but I's just too ugly and looks like a wrong walkthrough); 设置为null我不想要的响应属性(使用这个,但我太丑了,看起来像一个错误的演练);
    • or building HashMap like I build .json.jbuilder on Rails (but this kills my performance as sometimes it has relationships so a lot of for to build the json, and also this looks like a ugly walkthrough). 或建筑物HashMap就像我建.json.jbuilder on Rails的(但有时它也有关系,所以很多的这个杀死我的表现for打造JSON,也这看起来像一个丑陋的演练)。

I'm looking for some directions from someone that someday may have encountered one of this problems because it's killing me not being able so solve problems that in my mind should not be this hard. 我正在寻找某人的某些指示,有朝一日可能会遇到其中一个问题,因为它让我无法解决问题,而在我看来这不应该是这么难。

EDIT 1 编辑1

Already tried to add optional = false on the @OneToOne annotation to solve the Eager load of OneToOne relationship as @snovelli suggested. 已经尝试在@OneToOne注释上添加optional = false来解决@snovelli建议的OneToOne关系的Eager负载。 Example: 例:

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

If the join column is not in the table to which a parent in a one-to-one association is mapped, then the association cannot be lazy . 如果连接列不在映射了一对一关联中的父级的表中,则该关联不能是惰性的 The reason is that JPA provider cannot determine whether to create the proxy, so that it can load the object when accessed later, or leave the null value. 原因是JPA提供程序无法确定是否创建代理,以便它可以在以后访问时加载对象,或保留null值。

Even if the association is not optional, JPA provider has to determine the id of the associated entity instance to store it in the proxy. 即使关联不是可选的,JPA提供者也必须确定关联实体实例的id以将其存储在代理中。 Thus it has to go to the associated table anyway. 因此,无论如何它必须转到相关的表。

Solutions: 解决方案:

  1. Byte code instrumentation . 字节代码检测 Not widely adopted approach though. 虽然没有广泛采用的方法。
  2. Use one-to-many and handle empty list as null , otherwise use list.get(0) . 使用一对多并将空列表处理为null ,否则使用list.get(0) You can of course encapsulate this in the entity class (getter returns the only element of the list or null ). 您当然可以将它封装在实体类中(getter返回列表的唯一元素或null )。 The drawback is that you will have to treat this as collection in JPQL queries. 缺点是您必须将其视为JPQL查询中的集合。
  3. Use @PrimaryKeyJoinColumn instead of a foreign key. 使用@PrimaryKeyJoinColumn而不是外键。 If the association is not optional ( optional = false ), then JPA provider knows that there is an associated child with the same PK, so it will just store the PK of the parent as the id of the child in the proxy. 如果关联不是可选的( optional = false ),则JPA提供程序知道存在具有相同PK的关联子级,因此它将仅存储父级的PK作为代理中子级的ID。 Obviously, you can't use two independent id generators for both of the entities, otherwise PKs may be different. 显然,您不能为两个实体使用两个独立的id生成器,否则PK可能不同。 This is the best approach if it meets your requirements. 如果它符合您的要求,这是最好的方法。
  4. Add the foreign key in the parent table also (making the relationship bidirectional in the database as well). 也可以在父表中添加外键(使数据库中的关系也是双向的)。 The drawback is that you now basically have two independent associations which you have to maintain. 缺点是你现在基本上有两个独立的关联,你必须维护。 Also, there is the performance cost of updating two tables instead of one (and the foreign keys have to be nullable). 此外,还有更新两个表而不是一个表的性能成本(并且外键必须可以为空)。
  5. Map parent entity to a database view that joins parent table with the child table and contains all parent columns plus id of child table: 将父实体映射到将父表与子表连接的数据库视图,并包含所有父列和子表的id:

     @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "<child id in the view>", insertable = false, updatable = false) private Child child; 

Regarding 'dynamic' JSON: Use DTOs . 关于'动态'JSON:使用DTO

This has the advantage of tailoring the objects to be serialized to the exact needs of the client consuming the resulting JSON. 这样做的好处是可以将要序列化的对象定制为消耗生成的JSON的客户端的确切需求。 Also, the domain model (Hibernate entities) is decoupled from the JSON (de)serialization logic, allowing the two to evolve independently. 此外,域模型(Hibernate实体)与JSON(de)序列化逻辑分离,允许两者独立发展。

Regarding @OneToOne : are you worried more by amount of data or multiple queries against the DB? 关于@OneToOne :您是否更担心数据量或针对数据库的多个查询?

In former case (if that's possible when using Spring Roo) you could try a workaround with @ManyToOne relation modelling (one-to-one is a special case of many-to-one, isn't it). 在前一种情况下(如果使用Spring Roo时可能),您可以尝试使用@ManyToOne关系建模(一对一是多对一的特殊情况,不是这样)。

In latter case you could use @Embeddable to decompose entity like User into multiple classes while keeping the data together in the DB, so only one query would be used to fetch it. 在后一种情况下,您可以使用@Embeddable将像User这样的实体分解为多个类,同时将数据保存在数据库中,因此只能使用一个查询来获取它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM