如何使用 Java Spring Boot 在不插入新值的情况下更新表中的现有值
Posted
技术标签:
【中文标题】如何使用 Java Spring Boot 在不插入新值的情况下更新表中的现有值【英文标题】:How to update existing value in table without inserting new using Java SpringBoot 【发布时间】:2019-03-29 17:13:07 【问题描述】:我有两张桌子,一张是父母,另一张是孩子。当我最初尝试保存时,如果父表中不存在值,我可以在两个表中插入值。但是在更新/插入子表中的值时,它正在插入重复值。
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RuleApi
Long id;
private String market;
private int modelYear;
private String vehicleLine;
private String vehicleLineName;
private String locale;
private String binding;
private String description;
private String createUser;
private String updateUser;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DescriptorSaveRequest
@Valid
@NotNull
RuleApi rule;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "MNAVS03_DESCRIPTOR_CONTEXT")
@EntityListeners(AuditingEntityListener.class)
public class DescriptorContext implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Setter(value = AccessLevel.NONE)
@Column(name = "NAVS03_DESCRIPTOR_CONTEXT_K")
private Long id;
@Column(name = "NAVS03_MARKET_N")
private String market;
@Column(name = "NAVS03_MODEL_YEAR_R")
private Integer modelYear;
@Column(name = "NAVS03_VEHICLE_LINE_C")
private String vehicleLine;
@Column(name = "NAVS03_VEHICLE_LINE_N")
private String vehicleLineName;
@Column(name = "NAVS03_LOCALE_N")
private String locale;
@Column(name = "NAVS03_CREATE_USER_C", nullable = false)
private String createUserId;
@CreationTimestamp
@Column(name = "NAVS03_CREATE_S")
private Timestamp createTimestamp;
@Column(name = "NAVS03_LAST_UPDT_USER_C", nullable = false)
private String updateUserId;
@UpdateTimestamp
@Column(name = "NAVS03_LAST_UPDT_S")
private Timestamp updateTimestamp;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "MNAVS04_DESCRIPTOR_RULE")
@EntityListeners(AuditingEntityListener.class)
public class DescriptorRule implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Setter(value = AccessLevel.NONE)
@Column(name = "NAVS04_DESCRIPTOR_RULE_K")
private Long id;
@JoinColumn(name = "NAVS03_DESCRIPTOR_CONTEXT_K", nullable = false)
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private DescriptorContext descriptorContextId;
@Column(name = "NAVS04_BINDING_N",
unique = true)
private String binding;
@Column(name = "NAVS04_DESCRIPTOR_RULE_X")
private String description;
@Column(name = "NAVS04_CREATE_USER_C", nullable = false)
private String createUserId;
@CreationTimestamp
@Column(name = "NAVS04_CREATE_S")
private Timestamp createTimestamp;
@Column(name = "NAVS04_LAST_UPDT_USER_C", nullable = false)
private String updateUserId;
@UpdateTimestamp
@Column(name = "NAVS04_LAST_UPDT_S")
private Timestamp updateTimestamp;
@ApiOperation(value = "Create/Update Feature Descriptions", notes = "Create/Update a descriptions based on the given input")
@PostMapping("/descriptor/saveFeatures")
public ResponseEntity<BaseBodyResponse<String>> saveFeatureDescriptions(@Valid @RequestBody DescriptorSaveRequest descriptorSaveRequest) throws Exception
this.descriptorContextService.saveFeatureDescriptions(
this.descriptorContextMapper.mapDescriptorContext(descriptorSaveRequest),
this.descriptorContextMapper.mapDescriptorRule(descriptorSaveRequest)
);
return ResponseEntity.ok(BaseBodyResponse.result("Saved Successfully"));
@Service
public class DescriptorContextService
//SaveFeatureDescriptions
public void saveFeatureDescriptions(DescriptorContext descriptorContext, DescriptorRule descriptorRule) throws Exception
DescriptorContext descriptorContext1 =
this.descriptorContextRepository.findByMarketAndModelYearAndVehicleLineAndVehicleLineNameAndLocale(
descriptorContext.getMarket(),
descriptorContext.getModelYear(),
descriptorContext.getVehicleLine(),
descriptorContext.getVehicleLineName(),
descriptorContext.getLocale());
if (descriptorContext1 == null)
// add a new context
descriptorContext1 = descriptorContextRepository.save(DescriptorContext.builder()
.market(descriptorContext.getMarket())
.modelYear(descriptorContext.getModelYear())
.vehicleLine(descriptorContext.getVehicleLine())
.vehicleLineName(descriptorContext.getVehicleLineName())
.locale(descriptorContext.getLocale())
.createUserId(descriptorContext.getCreateUserId())
.updateUserId(descriptorContext.getUpdateUserId())
.build());
Long contextId = descriptorContext1.getId();
List<DescriptorRule> rule = this.descriptorRuleRepository.findByDescriptorContextId(contextId);
if (rule.size() == 0)
// add a new rule
this.descriptorRuleRepository.save(DescriptorRule.builder()
.descriptorContextId(descriptorContext1)
.binding(descriptorRule.getBinding())
.description(descriptorRule.getDescription())
.createUserId(descriptorContext.getCreateUserId())
.updateUserId(descriptorContext.getUpdateUserId())
.build());
else
// update a existing rule
for (DescriptorRule descriptorRule1 : rule)
if (descriptorRule1.getBinding().equals(descriptorRule.getBinding()))
descriptorRule1.setDescription(descriptorRule.getDescription());
descriptorRule1.setupdateUserId(descriptorRule.getupdateUserId());
this.descriptorRuleRepository.save(descriptorRule1);
else
this.descriptorRuleRepository.save(DescriptorRule.builder()
.descriptorContextId(descriptorContext1)
.binding(descriptorRule.getBinding())
.description(descriptorRule.getDescription())
.createUserId(descriptorContext.getCreateUserId())
.updateUserId(descriptorContext.getUpdateUserId())
.build());
@Component
public class DescriptorContextMapper
public DescriptorContext mapDescriptorContext(DescriptorSaveRequest descriptorSaveRequest)
return DescriptorContext.builder()
.market(descriptorSaveRequest.getRule().getMarket())
.vehicleLine(descriptorSaveRequest.getRule().getVehicleLine())
.vehicleLineName(descriptorSaveRequest.getRule().getVehicleLineName())
.modelYear(descriptorSaveRequest.getRule().getModelYear())
.locale(descriptorSaveRequest.getRule().getLocale())
.createUserId(descriptorSaveRequest.getRule().getCreateUser())
.updateUserId(descriptorSaveRequest.getRule().getUpdateUser())
.build();
public DescriptorRule mapDescriptorRule(DescriptorSaveRequest descriptorSaveRequest)
return DescriptorRule.builder()
.id(descriptorSaveRequest.getRule().getId())
.binding(descriptorSaveRequest.getRule().getBinding())
.description(descriptorSaveRequest.getRule().getDescription())
.createUserId(descriptorSaveRequest.getRule().getCreateUser())
.updateUserId(descriptorSaveRequest.getRule().getUpdateUser())
.build();
"rule":
"binding": "5003",
"description": "Test new 5003-2023 Escape",
"locale": "fr_CA",
"market": "WANAC",
"modelYear": 2023,
"vehicleLine": "TMC",
"vehicleLineName": "Escape",
"createUser": "rdongre",
"updateUser": "rdongre"
如果我传递了这个请求并且两个表中都不存在值,那么它应该在两个表中插入值,这与上面的代码按预期工作。但是在更新时,它会进入循环并插入重复值。如果存在 BINDING,我正在尝试更新子表中的说明,如果不存在,则应插入 BINDING 和说明
【问题讨论】:
大部分代码都不需要,导致问题不可读 我应该删除什么使其可读? 可以复制的最小例子会很棒:***.com/help/mcve 如果设置了 id,那么应该更新现有记录。如果未设置,则应创建新记录。我没有看到您在保存之前在实体上设置 id 的位置? 我在两个表中都有 id 列: Parent table: name = "NAVS03_DESCRIPTOR_CONTEXT_K") private Long id;子表:(name = "NAVS04_DESCRIPTOR_RULE_K") private Long id; JoinColumn(name = "NAVS03_DESCRIPTOR_CONTEXT_K", nullable = false) ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) private DescriptorContext 描述符ContextId; 【参考方案1】:我通过分离保存和更新方法解决了这个问题。谢谢大家。
【讨论】:
以上是关于如何使用 Java Spring Boot 在不插入新值的情况下更新表中的现有值的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot - 如何在不使用 spring 注释的情况下在运行时获取端口
如何在不使用 Spring Boot 的情况下注入 Feign Client 并调用 REST Endpoint
是否可以在不使用 Spring Boot JPA 的情况下测试基于 java 的 CRUD?
如何在不重启 Spring Boot 的情况下使用 Spring Security 添加新用户
如何在不从 spring-boot-starter-web 继承的情况下在 Spring Boot 中获取 ObjectMapper 实例?