Autowired Repository обновляет существующий объект вместо создания нового

После того, как я создаю первого агента в стране, я не могу создать нового агента, я просто обновляю первый агент. Если я создам первого агента, а затем удалю его, следующие агенты будут созданы нормально. Я включил режим отладки в настройках спящего режима, чтобы показать, что спящий режим действительно обновляет существующую запись в базе данных, а не создает новую.

Репозиторий

@Repository
public interface AgentsRepository extends JpaRepository<Country, Long> {
}

Контроллер

@Autowired
private AgentsRepository agentsRepository;

@Autowired
private CountriesRepository countriesRepository;

// Add new agent
@GetMapping("/country/{id}/agent/add")
public String addNewAgent(@PathVariable(name = "id") String countryId, Model model){
    model.addAttribute("country_id", countryId);
    model.addAttribute("agent", new Agent());
    return "agent/add";
}

@PostMapping("/country/{id}/agents/new")
public String createAgent(@PathVariable(value = "id") String countryId, @ModelAttribute Agent agent){
    return countriesRepository.findById(Long.parseLong(countryId)).map(country -> {
        agent.setCountry(country);
        agentsRepository.save(agent);
        return "redirect:/country/" + countryId + "/show/agents";
    }).orElseThrow(() -> new ResourceNotFoundException("CountryId " + countryId + " not found"));
}

Класс страны

@Entity
@Table(name = "countries")
public class Country implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private String name;

Класс агента

@Entity
@Table(name = "agents")
public class Agent implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@NotNull
private String status = "classified";

@NotNull
private String first_name;

@NotNull
private String last_name;

@NotNull
@Max(value = 2147483647)
private Integer documents;

@NotNull
@Max(value = 8)
private Integer people_recruited;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "country_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIgnore
private Country country;

Агент, добавляющий HTML

    <form action = "#" th:action = "@{'/country/{id}/agents/new'(id=${country_id})}" th:object = "${agent}" method = "post">
        <p>Name: <input type = "text" th:field = "*{first_name}" /></p>
        <p>Surname: <input type = "text" th:field = "*{last_name}"></p>
        <p>Documents: <input type = "number" max = "2147483647" th:field = "*{documents}" /></p>
        <p>People recruited: <input  type = "number" max = "8" th:field = "*{people_recruited}"></p>
        <p><input type = "submit" value = "Submit" /> <input type = "reset" value = "Reset" /></p>
    </form>
save, вероятно, видит, что объект уже существует с вашим id, и поэтому выполняет обновление вместо вставки (поскольку вставка приведет к ошибке, нарушающей уникальность вашего поля id)
CollinD 03.02.2019 21:54

убедитесь, что id уникален

Deadpool 03.02.2019 21:55

Идентификатор @Deadpool уникален

Sam.L 03.02.2019 21:58

@CollinD, но у меня есть идентификатор автоинкремента, поэтому, когда я создаю новый агент, он имеет (или должен иметь уникальный идентификатор)

Sam.L 03.02.2019 21:59

Пожалуйста, добавьте определение SQL для вашей таблицы

Vüsal 04.02.2019 17:40

Я не создаю таблицы сам, я оставил меня в спящем режиме (если таблицы не существуют, спящий режим создает таблицы при запуске приложения)

Sam.L 04.02.2019 17:46
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
86
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

@ModelAttribute Agent agent

Вы передаете какой-либо идентификатор агента из модели (UI)? или попробуйте установить его на ноль в контроллере. Скорее всего, пользовательский интерфейс отправляет какой-то фиктивный идентификатор для Agent, который одинаков для всех Agents Поэтому JPA обновляет его.

нет, я передаю в модель только данные, идентификатор сгенерирован с использованием спящего режима model.addAttribute("agent", new Agent());, здесь я передаю пустую модель

Sam.L 04.02.2019 17:14
Ответ принят как подходящий

Попробуй это:

@PostMapping("/country/{id}/agents/new")
public String createAgent(@PathVariable(value = "id") String countryId, @ModelAttribute Agent agent){
    return countriesRepository.findById(Long.parseLong(countryId)).map(country -> {
        Agent agentToBeSaved = new Agent();
        agentToBeSaved.setCountry(country);
        agentToBeSaved.setStatus(agent.getStatus());
        agentToBeSaved.setFirstName(agent.getFirstName());
        agentToBeSaved.setDocuments(agent.getDocuments());
        agentToBeSaved.setPeopleRecruited(agent.getPeopleRecruited());
        agentsRepository.save(agentToBeSaved);
        return "redirect:/country/" + countryId + "/show/agents";
    }).orElseThrow(() -> new ResourceNotFoundException("CountryId " + countryId + " not found"));
}

И если это работает - тогда вы передаете какой-то идентификатор объекту агента из пользовательского интерфейса.

Проверьте место, куда вы отправляете запрос. Проблема в том, что вы передаете идентификатор своей модели, поэтому hibernate обновляет его, а не создает новый. Кстати, я бы порекомендовал иметь классы моделей, которые вы получаете от клиента, и сопоставлять их с вашими объектами. Это добавляет дополнительный уровень безопасности и дает вам лучший контроль над значениями поля вашей сущности.

Vüsal 04.02.2019 18:16

Я проверяю свой html и ничего не нашел. Кроме того, если я создам в html поле, подобное этому <input type = "text" th:field = "*{id}" readonly/> (это поле будет считывать идентификатор из полученной модели (всегда пусто, потому что я запрашиваю новую модель)) спящий режим начинает работать нормально

Sam.L 04.02.2019 18:38

Другие вопросы по теме