Форма, которая при обновлении текущего клиента удаляет информацию дочерней таблицы, связанную с родительской таблицей - PullRequest
0 голосов
/ 06 ноября 2018

В моем приложении Spring-boot, Java и Thymeleaf у меня есть форма, которая заполняется один раз новой информацией о клиенте и сохраняется в таблице базы данных SQL. Когда вы хотите отредактировать информацию этого клиента и нажать кнопку «Сохранить», в итоге происходит сохранение / обновление информации, а также удаление информации в дочерней таблице SQL, которая называется ResourceWebsiteAccess. Я не могу сказать, обновляет ли она информацию и есть ли проблема с дочерней таблицей, или она просто заменяет всю информацию о клиентах и, следовательно, удаляет информацию о дочерней таблице. Любые идеи, что идет не так и как это исправить?

Вот некоторые из форм HTML:

 <form enctype="multipart/form-data" th:action="${clientEndpoint}" method="post" th:object="${client}" class="tab-content">
   <div class="tab-pane" id="prospect-profile">
        <div th:replace="prospectProfile :: prospect-profile"></div>
   </div>
   <div class="tab-pane" id="affiliates">
       <div class="row">
           <h4>Affiliate Competency</h4>
           <br/>
           <div th:replace="affiliates/personalLines :: personal-lines"></div>
       </div>
       <hr/>
       <div class="row">
           <div th:replace="affiliates/commercialLines :: commercial-lines"></div>
           </div>
           <hr/>
    </div>
   <input id="submitButton"  type="submit" value="Save" name="save" class="btn btn-success finish" data-loading-text="Saved!" disabled="true"/><br/>
</form>

Это действие контроллера, которое происходит при нажатии кнопки «Сохранить».

@RequestMapping(value="/saveClient")
@ResponseBody
public JSONObject saveClient(Model model, @ModelAttribute(value="client") Client client)
  {
        Boolean saved=false;
        JSONObject response=new JSONObject();
        Client clientBeforeUpdate=clientRepository.findById(client.getId());
        if (clientBeforeUpdate!=null && !clientBeforeUpdate.getStatus().equals("active") && client.getStatus().equals("active"))
            client.setOnboardedDate(LocalDate.now());
        else if (!client.getStatus().equals("active"))
            client.setOnboardedDate(null);
        try{
            client=clientRepository.save(client);
            saved=true;
            response.put("clientId",client.getId());
        }catch (DataAccessException e) {
            e.printStackTrace();
            response.put("error",e.getLocalizedMessage());
            response.put("cause",e.getLocalizedMessage());
        }
        response.put("success",saved);
        return response;
    }

Клиентский репозиторий:

@Transactional
public interface ClientRepository extends CrudRepository<Client,Long>, JpaSpecificationExecutor {

    Client save(Client entity);

    List<Client> findByPrincipleNameContaining(String principleName);

    List<Client> findByNdaSent(Boolean ndaSent);

    List<Client> findByLegalNameContaining(String legalName);

    List<Client> findByYearsExperienceContaining(String yearsExperience);

    List<Client> findByLicenses(String licenses);

    Client findById(Long id);

    void delete(Client entity);

    List<Client> findAll();

    @Query("SELECT c FROM Client c Where c.status = 'active' AND ((c.contractExecuted=false OR c.agencyLicenseReceived=false OR c.eoReceived=false OR c.w9 =false OR c.directDepositCommissionAgreement=false) OR c.licenses!='Accident & Health' AND (c.producerAppointmentForm=false OR c.prepaymentAuthorizationAms360=false))")
    List<Client> findClientsMissingDocs();

    List<Client> findByNdaSentAndNdaSentDateBetween(Boolean ndaSent,LocalDate start,LocalDate end);

    List<Client> findByContractSubmittedAndContractSubmittedDateBetween(boolean b, LocalDate startOfMonth, LocalDate now);

    List<Client> findByStatus(String prospect);

}

Вот некоторые из client.java, модель для формы.

@Entity
@Table(name="Client")
@EntityListeners(AuditingEntityListener.class)
public class Client {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ClientId")
    private Long id;
    ...
    @OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    @JoinColumn(name = "client")
    private List<Employee> employees= new ArrayList<>();
    @OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    @JoinColumn(name = "client")
    private List<VendorService> vendorServices=new ArrayList<>();


    @OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    @JoinColumn(name="client")
    private List<ResourceWebsiteAccess> resourceWebsiteAccess=new ArrayList<>();

    public List<ResourceWebsiteAccess> getResourceWebsiteAccess() {
        return resourceWebsiteAccess;
    }

    public void setResourceWebsiteAccess(List<ResourceWebsiteAccess> resourceWebsiteAccess) {
        this.resourceWebsiteAccess = resourceWebsiteAccess;
    }
}

Вот модель ResourceWebsiteAccess, у нее нет отдельного контроллера, но он есть в репозитории

@Entity
@Table(name = "ResourceWebsiteAccess")
public class ResourceWebsiteAccess {

    @Override
    public String toString() {
        return  micrositeLink;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ResourceWebsiteAccessId")
    private Long id;
    private String micrositeLink;
    private String partnerPortalLink;
    @OneToOne
    @JoinColumn(name = "client")
    private Client client;
  ...    
}
Как я добавляю информацию в дочернюю таблицу через форму, которая использует этот контроллер:

    @RequestMapping(value="/settings/client/{id}")
    public String links(@PathVariable("id")Client client, Model model){
        ResourceWebsiteAccess access= accessRepository.findByClient(client);
        if (access==null)
            access= new ResourceWebsiteAccess();

        model.addAttribute("client",client);
        model.addAttribute("newUser",new ResourceWebsiteUser());
        model.addAttribute("users",repository.findByClient(client));
        model.addAttribute("access",access);
        return "settings";
    }

ResourceWebsiteAccess Repository:

@Transactional
public interface ResourceWebsiteAccessRepository extends CrudRepository<ResourceWebsiteAccess,Long>,JpaSpecificationExecutor {
    ResourceWebsiteAccess findByClient(Client client);

}

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

Поскольку вы сохраняли ResourceWebsiteAccess отдельно, добавьте вставляемое и обновляемое false в @ JoinColumn

@OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    @JoinColumn(name="client",insertable=false,updatable=false)
    private List<ResourceWebsiteAccess> resourceWebsiteAccess=new ArrayList<>();
0 голосов
/ 07 ноября 2018

В итоге я добавил @DynamicUpdate в модель, удалив OrphanRemoval = true; в модели и добавление client.setResourceWebsiteAccess (clientBeforeUpdate.getResourceWebsiteAccess ()); в контроллер. Эти три шага исправили мою проблему, и теперь все отображается. Благодаря @ AlianCruz

0 голосов
/ 06 ноября 2018

Проблема, с которой вы столкнулись, заключается в том, что вы обновляете все поля, в том числе те, которые в вашей форме равны нулю. Что вы действительно хотите сделать, это обновить только те значения, которые были изменены. Для этого вы можете использовать аннотацию @DynamicUpdate Hibernate для вашей сущности.

@Entity
@DynamicUpdate
@Table(name="Client")
@EntityListeners(AuditingEntityListener.class)
public class Client { ... }

Подробнее об этом можно прочитать в следующем блоге .

Еще один способ добиться того, что вы пытаетесь сделать, - это выбрать клиента по его идентификатору, а затем установить новые значения с теми, которые вы только что получили из своей формы.

@RequestMapping(value="/saveClient")
@ResponseBody
public JSONObject saveClient(Model model, 
@ModelAttribute(value="client") Client client) {
    Boolean saved=false;
    JSONObject response=new JSONObject();
    Client clientBeforeUpdate=clientRepository.findById(client.getId());
    if (clientBeforeUpdate!=null && !clientBeforeUpdate.getStatus().equals("active") && client.getStatus().equals("active"))
            clientBeforeUpdate.setOnboardedDate(LocalDate.now());
    else if (!client.getStatus().equals("active"))
            clientBeforeUpdate.setOnboardedDate(null);
    try{
        // Set the rest of the needed changes from your new client.
        clientBeforeUpdate=clientRepository.save(clientBeforeUpdate);
        saved=true;
        response.put("clientId",client.getId());
    }catch (DataAccessException e) {
        e.printStackTrace();
        response.put("error",e.getLocalizedMessage());
        response.put("cause",e.getLocalizedMessage());
    }
    response.put("success",saved);
    return response;
}
...