【问题标题】:Can't POST a collection无法发布收藏
【发布时间】:2014-08-12 22:44:36
【问题描述】:

我有一个简单的实体,它映射了一个集合。

@Entity
public class Appointment Identifiable<Integer>   {  

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonIgnore
    private Integer id;

    @Column(name="TRAK_NBR")
    private String trackNumber;

    @OneToMany(fetch =FetchType.EAGER, cascade= CascadeType.ALL)
    @JoinColumn(name="CNSM_APT_VER_WRK_I", nullable = false)
    private Set<Product> products = new HashSet<Product>();
}

@Entity
public class Product implements Identifiable<Integer> {

    @Id
    @Column(name = "CNSM_PRD_VER_WRK_I")
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonIgnore
    private Integer id;

    @Column(name = "PRD_MDL_NBR")
    private String model;

    @Column(name = "PRD_SPEC_DSC")
    private String description;
}

在我的应用程序中,当我只包含一个用于约会的 PagingAndSortingRepository 时。我可以使用以下有效负载调用 POST 命令。

{
  "trackNumber" : "XYZ123",
  "products": [
    {"model" : "MODEL",
     "description" : "NAME"
    }]
}

当我为 Product 添加 PagingAndSortingRepository 并尝试相同的 POST 时,我收到以下错误消息。

{
  "cause" : {
    "cause" : {
      "cause" : null,
      "message" : null
    },
    "message" : "(was java.lang.NullPointerException) (through reference chain: com..model.Appointment[\"products\"])"
  },
  "message" : "Could not read JSON: (was java.lang.NullPointerException) (through reference chain: com.model.Appointment[\"products\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.model.AppointmentVerification[\"products\"])"
}

My GET payload with both Repositories returns this.  This is my desired format.  The link to products should be included

{
  "trackNumber" : "XYZ123", 
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/consumerappointment/appointments/70"
    },
    "products" : {
      "href" : "http://localhost:8080/consumerappointment/appointments/70/products"
  }
}

仅使用 Appointment 存储库,我可以获得以下有效负载并可以发布产品列表。

{
  "trackNumber" : "XYZ123",
  "products" : [ {
    "model" : "MODEL",
    "description" : "NAME",
  } ],
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/consumerappointment/appointments/1"
    }
  }
}

【问题讨论】:

    标签: spring-data-rest


    【解决方案1】:

    让我们退后一步,确保您了解这里发生的情况:如果检测到存储库,Spring Data REST 会公开一个dedicated set of resources 以便它管理存储库通过 HTTP 处理的聚合。因此,如果您有多个相互关联的实体的存储库,则关系将表示为链接。这就是为什么您在创建 ProductRepository 后看到内联的产品仅包含 AppointmentRepositoryproducts 链接的原因。

    如果要将两个存储库都公开为资源,则需要将 Product 实例的 URI 传递给 POST 的负载,以创建 Appointment。这意味着,而不是发布这个:

    { "trackNumber" : "XYZ123",
      "products": [
        { "model" : "MODEL",
          "description" : "NAME"
        }
      ]
    }
    

    你首先要创建一个Product

    POST /products
    { "model" : "MODEL",
      "description" : "NAME" }
    
    201 Created
    Location: …/products/4711
    

    然后将产品的ID交给Appointmentpayload:

    { "trackNumber" : "XYZ123",
      "products": [ "…/products/4711" ]}
    

    如果您不想要任何这些(首先没有为Product 公开资源,请在PersonRepository 上使用@RepositoryRestResource(exported = false)。这仍然会给您留下为repo 创建的bean 实例,但是没有资源被导出,并且为Appointments 暴露的资源返回到内联相关的Products。

    【讨论】:

    • 我明白了,从上面的代码中看不出来。我当然不了解您的数据库设计的细节,而是外键,并不意味着必须首先设置它。它可能只是将产品与稍后的约会联系起来的参考(因此您的Set)。也就是说,我试图解释为什么它可以正常工作。该模型完全有可能与您的用例不匹配,但您不必根据定义分离彼此之间具有双向关系的聚合根。
    • 我的产品表有一个外键约束回到约会表。所以先创造产品是行不通的。当我拥有两个存储库时,我可以超越 POST 的行为吗?我需要能够在同一事务中创建约会和产品,但在 GET 中仍然具有指向产品的链接。
    • 是的,只需为适当的路径和 HTTP 方法提供手动实现的控制器就可以了。不过,我认为这掩盖了一个基本的设计问题。
    • 我用我们谈到的手动实现的控制器创建了一个小应用程序。我仍然无法像我想的那样发布完整的有效载荷。好像我遇到了与jira.spring.io/browse/DATAREST-377 相同的问题。我的示例代码可以在github.com/zachariahyoung/posterror找到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    相关资源
    最近更新 更多