RequestMapping无法填充EmbeddedId中字段的实体类

时间:2015-11-13 02:34:45

标签: java spring hibernate spring-mvc spring-data

我有以下实体类:

@Entity
@Table(name="reporteddevicedata", schema="schemaName")
public class MobileDeviceData {

    @EmbeddedId 
    MobileDeviceDataId mobileDeviceDataId;

    @Column(name="activitydetecteddate")
    private ZonedDateTime activityDetectedDate;

    public void setFlagId(int flagId) {
        mobileDeviceDataId.setFlagId(flagId);
    }

    ......
}

@Embeddable
class MobileDeviceDataId implements Serializable {
    @Column(name="clientid")
    private int clientId;

    @Column(name="flagid")
    private int flagId;
}

我的Controller代码如下所示:

@RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Object> flagDevice (@RequestBody List<MobileDeviceData> deviceInfoList) {
    // code here
}

最初我的Entity课程只有@ID上的一个主键clientId而且效果很好。我会进行REST调用,它将按预期填充MobileDeviceData类。然后,我使用@Embeddable@EmbeddableId注释切换到复合ID,现在@RequestMapping无法填充flagId参数。现在当我进行REST调用时,我得到mobileDeviceDataId的空指针异常,因此在调用它时无法更新该字段并抛出空指针异常。

所以我的问题是,如何获得@Embeddable类的实例?我可以用new创建一个吗?我不确定这个含义,因为Spring可能期望自己创造这个价值?通过RequestMapping来更新此字段的“正常”方式是什么?

1 个答案:

答案 0 :(得分:0)

首先,你应该避免使用嵌入式ID,它只会让所有事情变得更难

代理主键更容易使用,当您在具有多列主键的表上使用外键时,处理它会变得更加复杂

现在你自己面对这些问题,但根据你的问题

@RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Object> flagDevice (@RequestBody List<MobileDeviceData> deviceInfoList) {
    for(MobileDeviceData mobileDeviceData : deviceInfoList){
        int clientId = mobileDeviceData.getMobileDeviceDataId().getClientId();
        int flagId = mobileDeviceData.getMobileDeviceDataId().getFlagId();
        MobileDeviceData foundMobileDeviceData = mobileDeviceDataService.findByClientIdAndFlagId(clientId, flagId);
        if(foundMovileDeviceData == null){
            mobileDeviceDataService.save(mobileDeviceData);
        }else {
            //update foundMobileDeviceData with mobileDeviceData  fields
            mobileDeviceDataService.save(foundMobileDeviceData);
        }
    }
}

否则,如果您只想更新标志ID

@RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Object> flagDevice (@RequestBody List<MobileDeviceData> deviceInfoList) {
    for(MobileDeviceData mobileDeviceData : deviceInfoList){
        int clientId = mobileDeviceData.getMobileDeviceDataId().getClientId();
        MobileDeviceData foundMobileDeviceData = mobileDeviceDataService.findByClientId(clientId);
        if(foundMovileDeviceData == null){
            mobileDeviceDataService.save(mobileDeviceData);
        }else {
            //update foundMobileDeviceData with mobileDeviceData 
            int flagId  = foundMobileDeviceData.getMobileDeviceDataId().getFlagId();
            MobileDeviceDataId mobileDeviceDataId = foundMobileDeviceData.getMobileDeviceDataId();
            mobileDeviceDataId.setFlagId(mobileDeviceData)

            mobileDeviceDataService.save(foundMobileDeviceData);
        }
    }
}

接下来,如果您想通过客户端ID查找内容,只需创建一个JPA查询,如

"from MobileDeviceData WHERE mobileDeviceDataId.clientId = :clientId"

或native sql

"SELECT * FROM reporteddevicedata WHERE client_id = :someParam"

示例JSON请求

[ {
  "mobileDeviceDataId" : {
    "clientId" : 0,
    "flagId" : 0
  },
  "activityDetectedDate" : null
}, {
  "mobileDeviceDataId" : {
    "clientId" : 1,
    "flagId" : 1
  },
  "activityDetectedDate" : null
}, {
  "mobileDeviceDataId" : {
    "clientId" : 2,
    "flagId" : 2
  },
  "activityDetectedDate" : null
} ]

uglified准备复制/粘贴版本:

[{"mobileDeviceDataId":{"clientId":0,"flagId":3},"activityDetectedDate":null},{"mobileDeviceDataId":{"clientId":1,"flagId":1},"activityDetectedDate":null},{"mobileDeviceDataId":{"clientId":2,"flagId":2},"activityDetectedDate":null}]

另外,您的MobileData对象应该添加一些验证,以避免在发送无效的json请求时出现无效指针(没有存在mobileDeviceDataId)

最后回答问题:

使用数据库模型作为容器在API之间共享并不是一个好习惯(因为主键,可能是一些敏感数据,取决于它)。

此外,如果您希望您的embeddableId工作,请求必须像示例json一样构建。必须填写适当的字段。当请求不是以这种方式构建而且它们只是扁平的json而没有&#39;嵌入的id&#39;你必须创建一些适合json格式的包装器(这个包装器将是requestbody类或List)。接下来,您必须将包装器转换为具有嵌入式ID的db对象(使用new关键字创建)。 这就是为什么我建议你不要使用复合或嵌入式ID。这是一个简单的例子,你只有一个表,但是当使用外键和多列主键时,表格变得越来越复杂和混乱,你更难以搜索db这就是为什么我建议你使用代理没有嵌入任何东西,它会使事情变得更加困难而且只是凌乱