【问题标题】:RequestMapping Unable to populate Entity class where fields within EmbeddedIdRequestMapping 无法填充 EmbeddedId 中的字段的实体类
【发布时间】:2016-02-14 13:54:16
【问题描述】:

我有以下实体类:

@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 类在clientId 上只有一个主键@ID,效果很好。我会进行 REST 调用,它会按预期填充 MobileDeviceData 类。然后我使用@Embeddable@EmbeddableId 注释切换到复合ID,现在@RequestMapping 无法填充flagId 参数。现在,当我进行 REST 调用时,我得到了 mobileDeviceDataId 的空指针异常,因此它在被调用时无法更新该字段并引发空指针异常。

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

【问题讨论】:

  • 您的错误显示在哪里?当您尝试放置数据时会发生这种情况吗?添加一些您发送的示例请求正文,然后我可能会帮助您弄清楚
  • @OskarDajnowicz - 我已经更新了这个问题。将 Spring 日志设置为调试向我展示了错误是什么。所以现在我只想知道如何更新 Embeddable 类中的字段的预期方式或“最佳实践”。

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


【解决方案1】:

首先你应该避免嵌入 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);
        }
    }
}

else 如果你想只更新标志 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"

或原生 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 中那样构建请求。必须填写正确的字段。当请求不是以这种方式构建并且它们只是没有“嵌入式 id”的平面 json 时,您必须创建一些适合 json 格式的包装器(这个包装器将是 requestbody 类或列表)。接下来,您必须将包装器转换为具有嵌入式 id 的 db 对象(使用新关键字创建)。 这就是为什么我建议您不要使用复合或嵌入式 id。这是一个简单的例子,你只有一个表,但是当涉及到使用外键和多列主键时,表变得更加复杂和混乱,你使搜索数据库变得更加困难,这就是为什么我建议你使用代理id 没有嵌入任何东西,它使事情变得更难而且很乱

【讨论】:

  • 我认为这是您问题的答案,还是我还遗漏了什么?
猜你喜欢
  • 2018-06-26
  • 2018-10-13
  • 1970-01-01
  • 2014-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
相关资源
最近更新 更多