Двунаправленное отношение OneToMany-ManyToOne со ссылкой на несохраненный переходный экземпляр (Spring MVC - Thymeleaf) - PullRequest
0 голосов
/ 11 июля 2020

новых здесь. Я новичок в Spring и Thymeleaf, я пытаюсь научиться, следя за видео, и я не знаю, почему я получаю следующее исключение (org.hibernate.TransientPropertyValueException: объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед flushing: org.launchcode.codingevents.models.Event.eventCategory -> org.launchcode.codingevents.models.EventCategory), когда я пытаюсь создать событие, присвоив ему EventCategory в форме Thymeleaf. Я пробовал каскадировать с одной стороны, затем с другой, а затем с обеих, но это не сработало.

Я буду безмерно благодарен всем, кто мне поможет.

Вот мой код .

@MappedSuperclass
public abstract class AbstractEntity {

    @Id
    @GeneratedValue
    private int id;

    public int getId() {
        return id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        AbstractEntity entity = (AbstractEntity) obj;
        return this.id == entity.id;
    }

@Entity
public class Event extends AbstractEntity {

    @NotBlank(message = "Name is required")
    @Size(min = 3, max = 50, message = "Name must be between 3 and 50 characters")
    private String name;
    @Size(max = 500, message = "Description too long!")
    private String description;

    @NotBlank(message = "Email is required")
    @Email(message = "Invalid email. Try again")
    private String contactEmail;
    
    @ManyToOne
    @NotNull(message = "Category is required")
    private EventCategory eventCategory;

    public Event() {

    }

    public Event(String name, String description, String contactEmail, EventCategory eventCategory) {
        this.name = name;
        this.description = description;
        this.contactEmail = contactEmail;
        this.eventCategory = eventCategory;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getContactEmail() {
        return contactEmail;
    }

    public void setContactEmail(String contactEmail) {
        this.contactEmail = contactEmail;
    }

    public EventCategory getEventCategory() {
        return eventCategory;
    }

    public void setEventCategory(EventCategory eventCategory) {
        this.eventCategory = eventCategory;
    }

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


@Entity
public class EventCategory extends AbstractEntity implements Serializable {

    @Size(min = 3, message = "Name must be at least 3 characters long")
    private String name;

    @OneToMany(mappedBy = "eventCategory")
    private final List<Event> events = new ArrayList<>();

    public EventCategory() {
    }

    public EventCategory(@Size(min = 3, message = "Name must be at least 3 characters long") String name) {
        this.name = name;
    }

    public List<Event> getEvents() {
        return events;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;


@Controller
@RequestMapping("events")
public class EventController {

    @Autowired
    private EventRepository eventRepository;

    @Autowired
    private EventCategoryRepository eventCategoryRepository;

    @GetMapping
    public String displayAllEvents(@RequestParam(required = false) Integer categoryId, Model model) {

        if (categoryId == null) {
            model.addAttribute("title", "All Events");
            model.addAttribute("events", eventRepository.findAll());
        } else {
            Optional<EventCategory> result = eventCategoryRepository.findById(categoryId);
            if (!result.isPresent()) {
                model.addAttribute("title", "Invalid Category Id: " + categoryId);
            } else {
                EventCategory category = result.get();
                model.addAttribute("title", "Events in Category: " + category.getName());
                model.addAttribute("events", category.getEvents());
            }
        }

        return "events/index";
    }

    // Lives at /events/create
    @GetMapping("create")
    public String displayCreateEventForm(Model model) {
        model.addAttribute("title", "Create Event");
        model.addAttribute(new Event());
        model.addAttribute("categories", eventCategoryRepository.findAll());
        return "events/create";
    }

    // lives at /events/create
    @PostMapping("create")
    public String processCreateEventForm(@Valid @ModelAttribute("newEvent") Event newEvent, Errors errors, Model model) {

        if (errors.hasErrors()) {
            model.addAttribute("title", "Create Event");
            return "events/create";
        }
        model.addAttribute("events", eventRepository.findAll());
        eventRepository.save(newEvent);
        return "redirect:";
    }

    // lives at /events/delete
    @GetMapping("delete")
    public String displayDeleteEventForm(Model model) {
        model.addAttribute("title", "Delete Events");
        model.addAttribute("events", eventRepository.findAll());
        return "events/delete";
    }

    // lives at /events/delete
    @PostMapping("delete")
    public String processDeleteEventForm(@RequestParam(required = false) int[] eventIds) {
        if (eventIds != null) {
            for (int id : eventIds) {
                eventRepository.deleteById(id);
            }
        }
        return "redirect:";
    }
}


Создать событие

<nav th:replace="fragments :: navigation"></nav>

<form method="post" th:action="@{/events/create}" th:object="${event}">
    <div class="form-group">
        <label>Name
            <input class="form-control" th:field="${event.name}">
        </label>
        <p class="error" th:errors="${event.name}"></p>
    </div>
    <div class="form-group">
        <label>Description
            <input class="form-control" th:field="${event.description}">
        </label>
        <p class="error" th:errors="${event.description}"></p>
    </div>
    <div class="form-group">
        <label>Contact Email
            <input class="form-control" th:field="${event.contactEmail}">
        </label>
        <p class="error" th:errors="${event.contactEmail}"></p>
    </div>
    <div class="form-group">
        <label>Category
            <select th:field="${event.eventCategory}">
                <option th:each="eventCategory : ${categories}" th:value="${eventCategory.id}"
                    th:text="${eventCategory.name}">
                </option>
            </select>
            <p class="error" th:errors="${event.eventCategory}"></p>
        </label>
    </div>
    <div th:replace="fragments :: create-button"></div>
</form>

1 Ответ

0 голосов
/ 11 июля 2020

Согласно вашему коду, вы пытаетесь сохранить только объект Event и игнорируете EventCategory. Вам нужно установить Event в EventCategory, а в EventCategory - в Event и сделать каскадное сохранение.

Сначала добавьте свойство cascade в сущность Event, как показано ниже.

    @ManyToOne(cascade = CascadeType.ALL)
    @NotNull(message = "Category is required")
    private EventCategory eventCategory;

Затем в контроллере внесите следующие изменения.

@PostMapping("create")
public String processCreateEventForm(@Valid @ModelAttribute("newEvent") Event newEvent, Errors errors, Model model) {

        if (errors.hasErrors()) {
            model.addAttribute("title", "Create Event");
            return "events/create";
        }
        model.addAttribute("events", eventRepository.findAll());
        EventCategory eventCategory = newEvent.getEventCategory();
        eventCategory.setEvent(newEvent);
        eventRepository.save(newEvent);
        return "redirect:";
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...