Search code examples
javaspring-bootjpainsert-updatehibernate-onetomany

How to update existing value in table without inserting new using Java SpringBoot


I have two tables one is parent and other one is child. When I am trying to save initially, I am able to insert values in both the tables if values not present in Parent table. But at the time of update/insert the values in child table, it is inserting duplicate values.

@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"
  }
}

If I am passing this request and values are not present in both the tables then it should insert the values in both the tables which is working as expected with above code. But at the time of update it is going inside the loop and inserting duplicate values. I am trying to update DESCRIPTION in child table if BINDING is present if not it should insert BINDING plus DESCRIPTION


Solution

  • I fixed this by separating Save and Update methods. Thanks to all.