【问题标题】:Convert native (join) queries in jpa (Hibernate) to json将 jpa (Hibernate) 中的本机 (join) 查询转换为 json
【发布时间】:2019-01-22 02:31:26
【问题描述】:

我正在开发一个 Spring Boot 项目,并且正在使用 jpa 进行数据持久性。现在我有两个相互关联的表,用户和项目。一个用户可以拥有任意数量的项目,而一个项目只能由一个用户拥有。
这是我的 pojo:
用户

@Entity
@Table(name="users", uniqueConstraints = {
            @UniqueConstraint(columnNames = {
                "email"
            })
    })
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"}, allowGetters = true)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    @NaturalId
    @Column(unique = true)
    private String email;

    @NotBlank
    @JsonIgnore
    private String password;

    @NotBlank
    private String first_name;

    @NotBlank
    private String last_name;

    @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true)
    @JsonIgnore
    private Set<Item> items;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();


    @Column(nullable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    private Date createdAt;

    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @LastModifiedDate
    private Date updatedAt;

项目

@Entity
@Table(name="items")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"}, allowGetters = true)
public class Item {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    @NotNull
    private String name;

    private String description;

    @NotNull 
    private Date purchase_date;

    private double price;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "owner", nullable = true)
    private User owner;

    @Column(nullable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    private Date createdAt;

    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @LastModifiedDate
    private Date updatedAt;

现在我想将所有项目作为 RESTfull JSON 获取。我需要将用户加入项目,以便获得以下 JSON:

{
    "item_id":1,
    "name":"item1",
    "price":120.00,

    etc .....

    "owner_id":1,
    "owner_name":"Jon"
    etc ....

}

所以我使用的是自定义原生查询

SELECT i.id, i.name, i.description ...... u.id, u.name ..... from items i , users u where i.owner = u.id

然后我返回 query.getResultList() 但是这返回的是字符串数组,而不是像这样的 json

[

    [ 1 , "item1" , 120.00 , ..... , 1 , "Jon" , ....]
    [ 2 , "item2" , 420.00 ....   ]
etc...
]

如何将返回的对象直接转换为 JSON,或者转换为将列名映射到值的映射列表,然后将其转换为 JSON?

【问题讨论】:

    标签: java json hibernate spring-mvc jpa


    【解决方案1】:

    您可以使用构造函数表达式来创建包含您需要的数据的 DTO(数据传输对象)。

    package dto;
    
    public class ItemDTO {
    
       private final Long item_id;
       private final String name;
       private final Long owner_id;
       private final String owner_name;
    
       public ItemDTO(Long item_id, String name, Long owner_id, String owner_name) {
          // set the fields
       }
    
       // getters
    }
    

    然后在构造函数表达式查询中使用这个 DTO(重要提示:这只适用于 JPQL 查询而不是原生查询)

    SELECT new dto.ItemDTO(i.id, i.name, i.owner.id, i.owner.name) from Item i where i.owner.id = u.id
    

    此 DTO 可用于序列化为 JSON。

    在此处阅读有关构造函数表达式的更多信息: https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/

    【讨论】:

    • 他还必须删除“nativeQuery = true”,因为您给出的示例是 JPQL 表达式。
    • 另外我会去检索整个对象,然后使用 MapStruct 之类的映射器构造 DTO...
    • @dbl 从性能的角度来看,构造函数表达式比读取实体和映射到 DTO 要好得多,因为它将只执行一条 SQL 语句,并且不会有 n+1 炸弹。跨度>
    • 这尤其适用于最终甚至需要分页的大型列表...但是如果列表像几个简单的对象并且请求的频率不高,那么我看不到任何好处那个。
    • 但这是否意味着我需要为每个查询编写一个新的 DTO 类?
    【解决方案2】:

    您可以使用它,不需要在每个请求上都添加新的 DTO。

    @SuppressWarnings("unchecked")
    public static List<ObjectNode> getQueryResult(EntityManager entityManager, String nativeQuery, Object... parameters) {
    
        Query localQuery = entityManager.createNativeQuery(nativeQuery,Tuple.class);
    
        for(int i = 0; i < parameters.length; i++)
            localQuery.setParameter(i+1, parameters[i]);
    
        return toJson(localQuery.getResultList());
    }
    
    private static List<ObjectNode> toJson(List<Tuple> results) {
    
        List<ObjectNode> json = new ArrayList<>();
    
        ObjectMapper mapper = new ObjectMapper();
    
        for (Tuple tuple : results)
        {
            List<TupleElement<?>> cols = tuple.getElements();
    
            ObjectNode node = mapper.createObjectNode();
    
            for (TupleElement col : cols)
                node.put(col.getAlias(), tuple.get(col.getAlias()).toString());
    
            json.add(node);
        }
        return json;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-11
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 2020-07-23
      • 2017-07-12
      • 2021-03-13
      • 2021-10-16
      • 2017-11-01
      相关资源
      最近更新 更多