【问题标题】:How to get object from OneToMany collection of objects?如何从对象的 OneToMany 集合中获取对象?
【发布时间】:2021-04-08 13:54:17
【问题描述】:

我有一个Order 实体和OrderProduct。我想在前端显示订单详细信息,当然还有订单产品。那么如何在OrderProduct JSON 中获取产品对象。我在产品数组中缺少产品对象。我不再需要订单对象,我认为这将是一个无限递归的东西。 :)

我的Order 实体:

@Entity
@Getter
@Setter
@Table(name ="orders")
public class Order{

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

    private BigDecimal totalPrice;

    @OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JsonManagedReference(value="orders")
    private List<OrderProduct> products = new ArrayList<>();

    private int userId;

    @DateTimeFormat(pattern="dd/MM/yyyy")
    private Date date = new Date();

    @DateTimeFormat(pattern="dd/MM/yyyy")
    private Date deliveryDate;

    @Enumerated(EnumType.STRING)
    private OrderType orderType;

}

我的OrderProduct 实体:

@Entity
@Setter
@Getter
public class OrderProduct {

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

    @ManyToOne(fetch = FetchType.EAGER)
    @JsonBackReference(value="product")
    @JoinColumn(name = "product_id")
    private Product product;

    @ManyToOne
    @JsonBackReference(value="orders")
    @JoinColumn(name = "order_id")
    private Order order;

    private Integer quantity;
}

产品实体:

@Entity
@Getter
@Setter
public class Product {

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

    @Column(unique = true)
    private String name;

    private double price;

    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
    @JsonManagedReference(value="ingredients")
    private List<Ingredient> ingredients = new ArrayList<>();

    @OneToMany(mappedBy = "product",fetch = FetchType.EAGER)
    @JsonManagedReference(value="product")
    private List<OrderProduct> products = new ArrayList<>();

    private String fileName;

}

【问题讨论】:

    标签: java json spring hibernate jpa


    【解决方案1】:

    这有助于用

    注释您的一个实体类
    @JsonIdentityInfo(
        property = "id",
        generator = ObjectIdGenerators.PropertyGenerator.class
    )
    

    每次 JSON 序列化循环时,对象数据都会被替换为对象 id 或实体字段供您选择。

    【讨论】:

    • 不幸的是,这对我不起作用。我试过这个。我已将此代码分别添加到我的实体中,它仍然是相同的。我仍然缺少 products[] 中的产品对象。
    【解决方案2】:

    您可以使用@JsonViewannotation 来定义需要序列化为 JSON 的字段

    它是如何工作的:

    1. 您需要使用接口定义类。例如:

      public class SomeView {
      
          public interface  id {}
      
          public interface CoreData extends id {}
      
          public interface FullData extends CoreData {}
      
      }
      
    2. @JsonView(&lt;some interface.class&gt;)标记实体字段

      public class User {
      
          @Id
          @GeneratedValue(strategy = GenerationType.AUTO)
          @JsonView(SomeView.id.class)
          private Long id;
      
          @Column(nullable = false)
          @JsonView(SomeView.CoreData.class)
          private String username;
      
          @Column(nullable = false)
          @JsonView(SomeView.FullData.class)
          private String email;
      }
      
    3. @JsonView(&lt;some interface.class&gt;)注释端点

       @GetMapping()
       @JsonView(<some interface.class>)
       public User getUser() {
           return <get user entity somwhere>
       }
      

    如果@JsonView(SomeView.id.class) 你会得到这个 JSON:

        {
            id: <some id>
        }
    

    万一@JsonView(SomeView.CoreData.class)

        {
            id: <some id>,
            username: <some username>
        }
    

    万一@JsonView(SomeView.FullData.class)

        {
            id: <some id>,
            username: <some username>,
            email: <some email>
        }
    

    @JsonView 也适用于嵌入对象,您可以使用多个视图类注释一个字段 - @JsonView({SomeView.FullData.class, SomeOtherView.OtherData.class})

    在你的情况下,我认为你应该注释你需要的所有字段,除了:

    @OneToMany(mappedBy = "product",fetch = FetchType.EAGER)
    @JsonManagedReference(value="product")
    private List<OrderProduct> products = new ArrayList<>();
    

    Product

    避免循环序列化

    或者作为替代方案,您可以只使用 DTO 类或手动将 oject 序列化为 JSON (https://thepracticaldeveloper.com/java-and-json-jackson-serialization-with-objectmapper/)

    【讨论】:

      【解决方案3】:

      这可以通过我的图书馆beanknife来完成

      // This configure generate a class named ProductInfo which has the same shape with Product without property "products"
      @ViewOf(value = Product.class, genName="ProductInfo", includePattern = ".*", excludes = {"products"})
      class ProductInfoConfigure {}
      
      // This configure generate a class named OrderProductRelation with the same shape of OrderProduct.
      // But it has not order property and the type of its product property is change to ProductInfo generated above.
      @ViewOf(value = OrderProduct.class, genName="OrderProductRelation", includePattern = ".*", excludes = {"order"})
      class OrderProductRelationConfigure {
          @OverrideViewProperty("product")
          private ProductInfo product;
      }
      
      // This configure generate a class named OrderDetail with the same shape of Order. 
      // But the type of its products property is change to List<OrderProductRelation>
      @ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
      class OrderDetailConfigure {
          @OverrideViewProperty("products")
          private List<OrderProductRelation> products;
      }
      
      

      将生成这些类:

      class ProductInfo {
          private Long id;
          private String name;
          private double price;
          private List<Ingredient> ingredients; // it is not processed because you have not provide the class Ingredient
          private String fileName;
      }
      
      public class OrderProductRelation {
          private Long id;
          private ProductInfo product;
          private Integer quantity;
      }
      
      public class OrderDetail {
          public Long id;
          private BigDecimal totalPrice;
          private List<OrderProductRelation> products;
          private int userId;
          private Date date = new Date();
          private Date deliveryDate;
          private OrderType orderType;
      }
      

      然后

      Order order = ...
      OrderDetail orderDetail = OrderDetail.read(order);
      // serialize the otherDetail instead of order.
      
      List<Order> orders = ...
      List<OrderDetail> orderDetails = OrderDetail.read(orders);
      // serialize the orderDetails instead of orders.
      

      可能的问题:

      1. 我不使用 Lombok,因此可能需要调整 Lombok,因为它会动态更改字节码。但这不是什么大问题,如果有人提交问题并提供足够的用例,我会尝试调整它。
      2. 生成的类不继承原类的注解。在下一个版本中,我将提供一个 sulotion。此时,作为一种解决方法,我们可以使用自定义方法手动转换属性。比如
      @ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
      class OrderDetailConfigure {
          @OverrideViewProperty("products")
          private List<OrderProductRelation> products;
          @OverrideViewProperty("orderType")
          public static String orderType(Order source) {
              return source.getOrder().name();
          }
      }
      

      生成的类会改为

      public class OrderDetail {
          public Long id;
          private BigDecimal totalPrice;
          private List<OrderProductRelation> products;
          private int userId;
          private Date date = new Date();
          private Date deliveryDate;
          private String orderType;
      }
      

      更新 版本 1.2.0 发布。添加注解继承支持。

      @ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
      @UseAnnotation({DateTimeFormat.class, Enumerated.class, JsonProperty.class})
      class OrderDetailConfigure {
          @OverrideViewProperty("products")
          private List<OrderProductRelation> products;
      }
      

      生成

      public class OrderDetail {
          public Long id;
          private BigDecimal totalPrice;
          private List<OrderProductRelation> products;
          private int userId;
          @DateTimeFormat(pattern="dd/MM/yyyy")
          private Date date;
          @DateTimeFormat(pattern="dd/MM/yyyy")
          private Date deliveryDate;
          @Enumerated(EnumType.STRING)
          private OrderType orderType;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-23
        • 2023-03-21
        • 1970-01-01
        • 2014-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多