如何使用 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 实例?

如何在不覆盖 Spring Boot 使用的情况下定义自定义 ObjectMapper bean