【问题标题】:JPA entity with ManyToOne relationship JSON Serialization具有多对一关系 JSON 序列化的 JPA 实体
【发布时间】:2014-04-28 11:40:43
【问题描述】:

我有两个由 OneToMany-ManyToOne 关系映射的 JPA 实体:

第一个实体:

@Entity(name = A.ENTITY_NAME)
@Table(name = A.TABLE_NAME)
@JsonIgnoreProperties(ignoreUnknown = true)
public class A implements Serializable{

    private static final long serialVersionUID = -24345893264589748L;

    public static final String TABLE_NAME = "A";
    public static final String ENTITY_NAME = "A";

    @Id
    @NotNull
    private String AName;

    private String ADescription;

    @OneToMany(fetch = FetchType.EAGER,mappedBy = "AName", cascade=CascadeType.ALL, orphanRemoval = true)
    @JsonIgnore(true)
    private List<B> b;

第二个实体:

@Entity(name = B.ENTITY_NAME)
@Table(name = B.TABLE_NAME)
public class B implements Serializable {

    private static final long serialVersionUID = -24345893264589748L;

    public static final String TABLE_NAME = "B";
    public static final String ENTITY_NAME = "B";

    @Id
    @NotNull
    private String BName;

    @ManyToOne
    @JoinColumn(name="AName")
    private AName;

    //Properties

我能够在我的 Oracle 数据库中创建表。

SQL> describe B;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 BNAME                                 NOT NULL VARCHAR2(255 CHAR)
...
 ANAME                                          VARCHAR2(255 CHAR)

现在我想在我的 Spring MVC 控制器中使用这些实体,如下所示:

@RequestMapping(value = B_CREATION_REQUEST_MAPPING, method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<JSONResponse> createB(HttpServletRequest request,
            @RequestBody B b) {


            BSvc.createB(b);
            ResponseEntity<JSONResponse> response = new ResponseEntity<JSONResponse>(new JSONResponse(), HttpStatus.OK);
            REST_LOGGER.info("[" + request.getRemoteAddr() + "] B object "+b.getBName()+ " has been created" );
            return response;
}

我对 A 对象有相同的控制器。

但是当我请求这个 B 控制器时,我必须在 JSON 中放入一个 A 对象,尽管请求无效:

{ 
  "BName": "foo",
  "AName": {"AName": "bar",
            "ADescription": "too"
            }
   ...
}

这会导致我出错:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing

我想要的只是放入我的 JSON 中:

 { 
      "BName": "foo",
      "AName": "bar",           
       ...
    }

而不是在 JSON 中创建对象 A。对象 A 之前是使用相同类型的控制器创建的,但我没有问题,因为没有外键。

我该如何解决这个问题?

【问题讨论】:

    标签: json entity-framework hibernate spring-mvc jpa


    【解决方案1】:

    为什么不创建一个专门用于 JSON 通信的对象而不是使用实体?

    你不能这样做:

    { 
          "BName": "foo",
          "AName": "bar",           
           ...
        }
    

    因为它会尝试将 String 反序列化为 A 对象

    创建一个 DTO 类

    class BDTO {
        private String AName;
        private String Bname
    }
    

    将它绑定到你的控制器 BDTO 而不是 B

    @RequestBody BDTO bDTO
    

    那你就可以了

    B b = new B();
    b.setBName(bDTO.getBName());
    b.setAName(yoursession.find(bDTO.getAName()));
    
    yoursession.saveOrUpdate(b);
    

    另一种解决方案:如果您想将 Entity 保留为 transfert 对象,请仅在您的请求中设置 ID:

    { 
      "BName": "foo",
      "AName": {"AName": "bar" }
       ...
    }
    

    您不必设置 AName 的所有子属性,只需 @ID 就足够了,在您的控制器中,您可以简单地为 A 对象执行 find() 并将其设置在 B 上,然后保存或更新您的 B 对象:

    b.setAName(yoursession.find(b.getAName().getAName()));
    

    【讨论】:

      【解决方案2】:

      从 Jackson 1.9 开始,您可以使用 @JsonUnwrapped 注释定义嵌套类字段,以向 Jackson 指示在序列化期间应解开包含的对象,即包含的对象属性应包含在父对象的属性中。

      public class B implements Serializable {
      

      ...

      @ManyToOne
      @JoinColumn(name="AName")
      @JsonUnwrapped
      private AName;
      

      【讨论】:

        猜你喜欢
        • 2012-12-17
        • 2013-11-20
        • 1970-01-01
        • 1970-01-01
        • 2015-06-16
        • 1970-01-01
        • 2012-09-29
        • 2012-11-25
        • 1970-01-01
        相关资源
        最近更新 更多