具有多对一关系JSON序列化的JPA实体



我有两个由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 ?

你不能这样做:

{ 
      "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);

另一个解决方案:如果你想保持实体作为传输对象是只设置ID在您的请求:

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

你不需要设置name的所有子属性只有@ID就足够了,在你的控制器中你可以简单地对a对象执行find()并将其设置为B然后saveOrUpdate你的B对象:

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

从Jackson 1.9开始,你可以用@JsonUnwrapped注释来定义你的嵌套类字段,以指示Jackson一个包含的对象应该在序列化期间取消包装,即包含的对象属性应该包含在父对象的属性中。

public class B implements Serializable {

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

最新更新