JPA存储库保存方法创建新实例,而不是合并

发布于 2025-01-17 11:53:35 字数 19198 浏览 4 评论 0原文

在我的项目中,有一些用户注册的活动。当用户注册事件时,事件容量会减少 1,并且用户名将添加到事件的 String 属性中。在我的代码中对事件进行这些更改后,我调用 eventsRepository.save(event),我认为这只是合并了新更新的事件,但由于某种原因,我的数据库只是创建了一个全新的事件具有新 ID 和新值的事件。

以下是该问题的一些图片:

用户注册之前的事件数据(包括存储库中的 UUID) 输入图片这里的描述

用户注册后的事件数据 输入图片此处的描述

用户代码:

import javax.persistence.Embeddable;
import javax.persistence.Entity;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;

import ymca.tracker.application.data.AbstractEntity;

@Embeddable
@Entity
public class User extends AbstractEntity {

    private boolean familyAccount;
    private String firstName;
    private String lastName;
    private String username;
    private String password;
    private String passwordSalt;
    private String passwordHash;
    private ymca.tracker.application.data.entity.Role role; 

    public User() {
        
    }

    public User(boolean familyAccount, String firstName, String lastName, 
        String username, String password, ymca.tracker.application.data.entity.Role role) {
        this.familyAccount = familyAccount;
        this.firstName = firstName;
        this.lastName = lastName;
        this.username = username;
        this.role = role;
        this.password = password;
        this.passwordSalt = RandomStringUtils.random(32);
        this.passwordHash = DigestUtils.sha1Hex(password + passwordSalt);
    }

    public boolean checkPassword(String password) {
        return DigestUtils.sha1Hex(password + passwordSalt).equals(passwordHash);
    }
    public boolean getFamilyAccount() {
        return familyAccount;
    }
    public void setFamilyAccount(boolean familyAccount) {
        this.familyAccount = familyAccount;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getPasswordSalt() {
        return passwordSalt;
    }
    public void setPasswordSalt(String passwordSalt) {
        this.passwordSalt = passwordSalt;
    }
    public String getPasswordHash() {
        return passwordHash;
    }
    public void setPasswordHash(String passwordHash) {
        this.passwordHash = passwordHash;
    }
    public ymca.tracker.application.data.entity.Role getRole() {
        return role;
    }
    public void setRole(ymca.tracker.application.data.entity.Role role) {
        this.role = role;
    }
}

事件代码:

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;

import ymca.tracker.application.data.AbstractEntity;

@Embeddable
@Entity
public class Events extends AbstractEntity {

    private String name;
    private java.time.LocalDate startDate;
    private java.time.LocalDate endDate;
    private java.time.LocalTime startTime;
    private java.time.LocalTime endTime;
    private String recurring;
    private int participants;
    private String nonMemberPrice;
    private String memberPrice;
    private String location;
    private String description;
    private String users;
    // Not currently used
    @ElementCollection
    @OneToMany(fetch = FetchType.LAZY)
    private List<User> registrants = new ArrayList<User>();

    public Events() {

    }

    public Events(String name, LocalDate startDate, LocalDate endDate, LocalTime startTime, LocalTime endTime, 
        String recurring, int participants, String nonMemberPrice, String memberPrice, String location, 
            String description, String users, List<User> registrants) {
            this.name = name;
            this.startDate = startDate;
            this.endDate = endDate;
            this.startTime = startTime;
            this.endTime = endTime;
            this.recurring = recurring;
            this.participants = participants;
            this.nonMemberPrice = nonMemberPrice;
            this.memberPrice = memberPrice;
            this.location = location;
            this.description = description;
            this.users = " ";
            this.registrants = registrants;
        }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public java.time.LocalDate getStartDate() {
        return startDate;
    }
    public void setStartDate(java.time.LocalDate startDate) {
        this.startDate = startDate;
    }
    public java.time.LocalDate getEndDate() {
        return endDate;
    }
    public void setEndDate(java.time.LocalDate endDate) {
        this.endDate = endDate;
    }
    public java.time.LocalTime getStartTime() {
        return startTime;
    }
    public void setStartTime(java.time.LocalTime startTime) {
        this.startTime = startTime;
    }
    public java.time.LocalTime getEndTime() {
        return endTime;
    }
    public void setEndTime(java.time.LocalTime endTime) {
        this.endTime = endTime;
    }
    public String getRecurring() {
        return recurring;
    }
    public void setRecurring(String recurring) {
        this.recurring = recurring;
    }
    public int getParticipants() {
        return participants;
    }
    public void setParticipants(int participants) {
        this.participants = participants;
    }
    public void decreaseCapacity(int numToDecreaseBy) {
        this.participants = this.participants - numToDecreaseBy;
    }
    public String getMemberPrice() {
        return memberPrice;
    }
    public void setMemberPrice(String memberPrice) {
        this.memberPrice = memberPrice;
    }
    public String getNonMemberPrice() {
        return nonMemberPrice;
    }
    public void setNonMemberPrice(String nonMemberPrice) {
        this.nonMemberPrice = nonMemberPrice;
    }
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getUsers() {
        return users;
    }
    public void setUsers(String users) {
        this.users = users;
    }
    public void addUser(String user) {
        this.users = this.users + user + "\n";
    }
    public List<User> getRegistrants() {
        return registrants;
    }
    public void setGuests(ArrayList<User> registrants) {
        this.registrants = registrants;
    }
    public void addRegistrant(User user) {
        this.registrants.add(user);
    }
    public void removeRegistrant(User user) {
        this.registrants.remove(user);
    }
    public boolean checkRegistrant(User user) {
        return this.registrants.contains(user);
    }
}

访客用户注册的代码位于此视图中(保存调用用注释标记)(使用 id 列代码更新):

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.Grid.SelectionMode;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.Notification.Position;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.orderedlayout.FlexComponent.Alignment;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import ymca.tracker.application.data.entity.Events;
import ymca.tracker.application.data.entity.Role;
import ymca.tracker.application.data.entity.User;
import ymca.tracker.application.data.service.EventsRepository;
import ymca.tracker.application.data.service.EventsService;
import ymca.tracker.application.data.service.UserRepository;
import ymca.tracker.application.views.MainLayout;

@PageTitle("Guest Events")
@Route(value = "guest-events", layout = MainLayout.class)
public class GuestEventsView extends Div { 

    private EventsService eventsService;
    private EventsRepository eventsRepository;
    private UserRepository userRepository;

    private Grid<Events> grid;
    private GridListDataView<Events> gridListDataView;

    private Grid.Column<Events> idColumn;
    private Grid.Column<Events> signUpColumn;
    private Grid.Column<Events> nameColumn;
    private Grid.Column<Events> startDateColumn;
    private Grid.Column<Events> endDateColumn;
    private Grid.Column<Events> startTimeColumn;
    private Grid.Column<Events> endTimeColumn;
    private Grid.Column<Events> recurringColumn;
    private Grid.Column<Events> participantsColumn;
    private Grid.Column<Events> priceColumn;
    private Grid.Column<Events> locationColumn;
    private Grid.Column<Events> descriptionColumn;

    public GuestEventsView(EventsService eventsService, EventsRepository eventsRepository, UserRepository userRepository) {
        this.eventsService = eventsService;
        this.eventsRepository = eventsRepository;
        this.userRepository = userRepository;
        addClassName("guest-events-view");
        setSizeFull();
        Button signUpButton = createSignUpButton();
        add(signUpButton);
        createGrid();
        add(grid);
    }

    private void createGrid() {
        createGridComponent();
        addColumnsToGrid();
    }

    private void createGridComponent() {
        grid = new Grid<>();
        grid.setSelectionMode(SelectionMode.SINGLE);
        grid.addThemeVariants(GridVariant.LUMO_NO_BORDER, GridVariant.LUMO_COLUMN_BORDERS);
        grid.setHeight("100%");

        List<Events> events = getEvents();
        gridListDataView = grid.setItems(events);
    }

    private void addColumnsToGrid() {
        createIdColumn();
        createNameColumn();
        createStartDateColumn();
        createEndDateColumn();
        createStartTimeColumn();
        createEndTimeColumn();
        createRecurringColumn();
        createParticipantsColumn();
        createPriceColumn();
        createLocationColumn();
        createDescriptionColumn();
    }

    private Button createSignUpButton() {
        // Create the Dialog object which will be the signUpForm
        Dialog signUpForm = new Dialog();
        // Create the layout for the signUpForm, passing in the Dialog and selected Event
        VerticalLayout signUpFormLayout = createSignUpFormLayout(signUpForm);
        // Add the created layout to the signUpForm
        signUpForm.add(signUpFormLayout);
        // Only the signUpForm can be interacted with when it appears on the screen
        signUpForm.setModal(true);

        Button signUpButton = new Button("Sign Up");
        signUpButton.addClickListener(e -> signUpForm.open());
        return signUpButton;
    }

    private VerticalLayout createSignUpFormLayout(Dialog signUpForm) {
        signUpForm.getElement().setAttribute("aria-label", "Registration Form");

        TextField firstName = new TextField("First Name");
        TextField lastName = new TextField("Last Name");

        H2 headline = new H2("Registration Form");
        headline.getStyle().set("margin-top", "0");

        Button cancel = new Button("Cancel", e -> signUpForm.close());
        Button submit = new Button("Submit", e -> {
            if(fillChecker(firstName.getValue(), lastName.getValue()) == true) {
                String fn = firstName.getValue();
                String ln = lastName.getValue();
                User guest = new User(false, fn, ln,
                    "null", "null", Role.GUEST);

                Set<Events> selected = grid.getSelectedItems();
                Events[] curEvent = selected.toArray(new Events[1]);
                Events selectedEvent = curEvent[0];

                if(selectedEvent == null) {
                    Notification.show("No Event Selected!", 5000, Position.TOP_CENTER);
                } else {
                    userRepository.save(guest); // Saves guest sign-up info to user repository
                    selectedEvent.addUser(fn + " " + ln);
                    selectedEvent.decreaseCapacity(1); // Decrease events participants count by 1
                    
                    // ISSUE HERE
                    // Currently saves new version of event instead of merging
                    UUID toDelete = selectedEvent.getId();
                    eventsRepository.save(selectedEvent);
                    eventsRepository.deleteById(toDelete);

                    signUpForm.close();

                    Notification.show("Registered 1 Guest", 5000, Position.TOP_CENTER);
                }                
            } else {
                Notification.show("Please complete the form to register", 5000, Position.TOP_CENTER);
            }
        });

        submit.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        HorizontalLayout buttonLayout = new HorizontalLayout(cancel, submit);
        buttonLayout.setAlignItems(Alignment.END);
        buttonLayout.getStyle().set("margin-top", "var(--lumo-space-m");
        VerticalLayout signUpFormLayout = new VerticalLayout(headline, firstName, lastName, buttonLayout);
        signUpFormLayout.setPadding(false);
        signUpFormLayout.setSpacing(false);
        signUpFormLayout.setAlignItems(Alignment.STRETCH);
        signUpFormLayout.getStyle().set("width", "18rem").set("max-width", "100%");

        return signUpFormLayout;
    }

    private boolean fillChecker(String firstName, String lastName) {
        if(firstName.equals("") || lastName.equals("")) {
            return false;
        }
        return true;
    }

    private void createIdColumn() {
        idColumn = grid.addColumn(Events::getId, "id").setHeader("ID").setAutoWidth(true);
    }

    private void createNameColumn() {
        nameColumn = grid.addColumn(Events::getName, "name").setHeader("Name").setAutoWidth(true);
    }

    private void createStartDateColumn() {
        startDateColumn = grid.addColumn(Events::getStartDate, "startDate").setHeader("Start Date").setAutoWidth(true);
    }

    private void createEndDateColumn() {
        startDateColumn = grid.addColumn(Events::getEndDate, "endDate").setHeader("End Date").setAutoWidth(true);
    }

    private void createStartTimeColumn() {
        startTimeColumn = grid.addColumn(Events::getStartTime, "startTime").setHeader("Start Time").setAutoWidth(true);
    }

    private void createEndTimeColumn() {
        startDateColumn = grid.addColumn(Events::getEndTime, "endTime").setHeader("End Time").setAutoWidth(true);
    }

    private void createRecurringColumn() {
        recurringColumn = grid.addColumn(Events::getRecurring, "recurring").setHeader("Recurring?").setAutoWidth(true);
    }

    private void createParticipantsColumn() {
        participantsColumn = grid.addColumn(Events::getParticipants, "participants").setHeader("Capacity").setAutoWidth(true);
    }

    private void createPriceColumn() {
        priceColumn = grid.addColumn(Events::getNonMemberPrice, "price").setHeader("Price").setAutoWidth(true);
    }

    private void createLocationColumn() {
        locationColumn = grid.addColumn(Events::getLocation, "location").setHeader("Location").setAutoWidth(true);
    }

    private void createDescriptionColumn() {
        descriptionColumn = grid.addColumn(Events::getDescription, "description").setHeader("Description").setAutoWidth(true);
    }

    private List<Events> getEvents() {
        List<Events> list = eventsService.findAllEvents();
        List<Events> toReturn = new ArrayList<Events>();
        Events e;
        int size = list.size();
        for(int i = 0; i < size; i++) {
            Events temp = list.get(i);
            e = createEvents(temp.getName(), temp.getStartDate(), temp.getEndDate(), temp.getStartTime(), temp.getEndTime(),
                temp.getRecurring(), temp.getParticipants(), temp.getNonMemberPrice(), temp.getLocation(), temp.getDescription());
            toReturn.add(e);
        }
        return toReturn;
    }

    private Events createEvents(String name, java.time.LocalDate startDate, java.time.LocalDate endDate, 
        java.time.LocalTime startTime, java.time.LocalTime endTime, String recurring, int participants, 
            String price, String location, String description) {

        Events e = new Events();
        e.setName(name);
        e.setStartDate(startDate);
        e.setEndDate(endDate);
        e.setStartTime(startTime);
        e.setEndTime(endTime);
        e.setRecurring(recurring);
        e.setParticipants(participants);
        e.setNonMemberPrice(price);
        e.setLocation(location);
        e.setDescription(description);

        return e;

    }
};

这是我的 AbstractEntity 类:

import java.util.UUID;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class AbstractEntity {

    @Id
    @GeneratedValue
    private UUID id;

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        if (id != null) {
            return id.hashCode();
        }
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof AbstractEntity)) {
            return false; // null or other class
        }
        AbstractEntity other = (AbstractEntity) obj;

        if (id != null) {
            return id.equals(other.id);
        }
        return super.equals(other);
    }
}

添加结果注册网格的 Id 列: 输入图片此处描述

In my project there are events that users sign up for. When a user signs up for an event, the events capacity decreases by 1 and the users name is added to a String attribute for the event. After these changes are made to the event in my code, I call eventsRepository.save(event), which I thought just merges the newly updated event, but for some reason my database is just creating a whole new event with a new ID with the new values.

Here are some pictures of the issue:

The event data before a user signs up (UUID in repository included)
enter image description here

The event data after a user signs up
enter image description here

Code for a User:

import javax.persistence.Embeddable;
import javax.persistence.Entity;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;

import ymca.tracker.application.data.AbstractEntity;

@Embeddable
@Entity
public class User extends AbstractEntity {

    private boolean familyAccount;
    private String firstName;
    private String lastName;
    private String username;
    private String password;
    private String passwordSalt;
    private String passwordHash;
    private ymca.tracker.application.data.entity.Role role; 

    public User() {
        
    }

    public User(boolean familyAccount, String firstName, String lastName, 
        String username, String password, ymca.tracker.application.data.entity.Role role) {
        this.familyAccount = familyAccount;
        this.firstName = firstName;
        this.lastName = lastName;
        this.username = username;
        this.role = role;
        this.password = password;
        this.passwordSalt = RandomStringUtils.random(32);
        this.passwordHash = DigestUtils.sha1Hex(password + passwordSalt);
    }

    public boolean checkPassword(String password) {
        return DigestUtils.sha1Hex(password + passwordSalt).equals(passwordHash);
    }
    public boolean getFamilyAccount() {
        return familyAccount;
    }
    public void setFamilyAccount(boolean familyAccount) {
        this.familyAccount = familyAccount;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getPasswordSalt() {
        return passwordSalt;
    }
    public void setPasswordSalt(String passwordSalt) {
        this.passwordSalt = passwordSalt;
    }
    public String getPasswordHash() {
        return passwordHash;
    }
    public void setPasswordHash(String passwordHash) {
        this.passwordHash = passwordHash;
    }
    public ymca.tracker.application.data.entity.Role getRole() {
        return role;
    }
    public void setRole(ymca.tracker.application.data.entity.Role role) {
        this.role = role;
    }
}

Code for an Events:

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;

import ymca.tracker.application.data.AbstractEntity;

@Embeddable
@Entity
public class Events extends AbstractEntity {

    private String name;
    private java.time.LocalDate startDate;
    private java.time.LocalDate endDate;
    private java.time.LocalTime startTime;
    private java.time.LocalTime endTime;
    private String recurring;
    private int participants;
    private String nonMemberPrice;
    private String memberPrice;
    private String location;
    private String description;
    private String users;
    // Not currently used
    @ElementCollection
    @OneToMany(fetch = FetchType.LAZY)
    private List<User> registrants = new ArrayList<User>();

    public Events() {

    }

    public Events(String name, LocalDate startDate, LocalDate endDate, LocalTime startTime, LocalTime endTime, 
        String recurring, int participants, String nonMemberPrice, String memberPrice, String location, 
            String description, String users, List<User> registrants) {
            this.name = name;
            this.startDate = startDate;
            this.endDate = endDate;
            this.startTime = startTime;
            this.endTime = endTime;
            this.recurring = recurring;
            this.participants = participants;
            this.nonMemberPrice = nonMemberPrice;
            this.memberPrice = memberPrice;
            this.location = location;
            this.description = description;
            this.users = " ";
            this.registrants = registrants;
        }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public java.time.LocalDate getStartDate() {
        return startDate;
    }
    public void setStartDate(java.time.LocalDate startDate) {
        this.startDate = startDate;
    }
    public java.time.LocalDate getEndDate() {
        return endDate;
    }
    public void setEndDate(java.time.LocalDate endDate) {
        this.endDate = endDate;
    }
    public java.time.LocalTime getStartTime() {
        return startTime;
    }
    public void setStartTime(java.time.LocalTime startTime) {
        this.startTime = startTime;
    }
    public java.time.LocalTime getEndTime() {
        return endTime;
    }
    public void setEndTime(java.time.LocalTime endTime) {
        this.endTime = endTime;
    }
    public String getRecurring() {
        return recurring;
    }
    public void setRecurring(String recurring) {
        this.recurring = recurring;
    }
    public int getParticipants() {
        return participants;
    }
    public void setParticipants(int participants) {
        this.participants = participants;
    }
    public void decreaseCapacity(int numToDecreaseBy) {
        this.participants = this.participants - numToDecreaseBy;
    }
    public String getMemberPrice() {
        return memberPrice;
    }
    public void setMemberPrice(String memberPrice) {
        this.memberPrice = memberPrice;
    }
    public String getNonMemberPrice() {
        return nonMemberPrice;
    }
    public void setNonMemberPrice(String nonMemberPrice) {
        this.nonMemberPrice = nonMemberPrice;
    }
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getUsers() {
        return users;
    }
    public void setUsers(String users) {
        this.users = users;
    }
    public void addUser(String user) {
        this.users = this.users + user + "\n";
    }
    public List<User> getRegistrants() {
        return registrants;
    }
    public void setGuests(ArrayList<User> registrants) {
        this.registrants = registrants;
    }
    public void addRegistrant(User user) {
        this.registrants.add(user);
    }
    public void removeRegistrant(User user) {
        this.registrants.remove(user);
    }
    public boolean checkRegistrant(User user) {
        return this.registrants.contains(user);
    }
}

Code for Guest Users to sign up located in this View (save call is marked with comment) (updated with id column code):

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.Grid.SelectionMode;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.Notification.Position;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.orderedlayout.FlexComponent.Alignment;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import ymca.tracker.application.data.entity.Events;
import ymca.tracker.application.data.entity.Role;
import ymca.tracker.application.data.entity.User;
import ymca.tracker.application.data.service.EventsRepository;
import ymca.tracker.application.data.service.EventsService;
import ymca.tracker.application.data.service.UserRepository;
import ymca.tracker.application.views.MainLayout;

@PageTitle("Guest Events")
@Route(value = "guest-events", layout = MainLayout.class)
public class GuestEventsView extends Div { 

    private EventsService eventsService;
    private EventsRepository eventsRepository;
    private UserRepository userRepository;

    private Grid<Events> grid;
    private GridListDataView<Events> gridListDataView;

    private Grid.Column<Events> idColumn;
    private Grid.Column<Events> signUpColumn;
    private Grid.Column<Events> nameColumn;
    private Grid.Column<Events> startDateColumn;
    private Grid.Column<Events> endDateColumn;
    private Grid.Column<Events> startTimeColumn;
    private Grid.Column<Events> endTimeColumn;
    private Grid.Column<Events> recurringColumn;
    private Grid.Column<Events> participantsColumn;
    private Grid.Column<Events> priceColumn;
    private Grid.Column<Events> locationColumn;
    private Grid.Column<Events> descriptionColumn;

    public GuestEventsView(EventsService eventsService, EventsRepository eventsRepository, UserRepository userRepository) {
        this.eventsService = eventsService;
        this.eventsRepository = eventsRepository;
        this.userRepository = userRepository;
        addClassName("guest-events-view");
        setSizeFull();
        Button signUpButton = createSignUpButton();
        add(signUpButton);
        createGrid();
        add(grid);
    }

    private void createGrid() {
        createGridComponent();
        addColumnsToGrid();
    }

    private void createGridComponent() {
        grid = new Grid<>();
        grid.setSelectionMode(SelectionMode.SINGLE);
        grid.addThemeVariants(GridVariant.LUMO_NO_BORDER, GridVariant.LUMO_COLUMN_BORDERS);
        grid.setHeight("100%");

        List<Events> events = getEvents();
        gridListDataView = grid.setItems(events);
    }

    private void addColumnsToGrid() {
        createIdColumn();
        createNameColumn();
        createStartDateColumn();
        createEndDateColumn();
        createStartTimeColumn();
        createEndTimeColumn();
        createRecurringColumn();
        createParticipantsColumn();
        createPriceColumn();
        createLocationColumn();
        createDescriptionColumn();
    }

    private Button createSignUpButton() {
        // Create the Dialog object which will be the signUpForm
        Dialog signUpForm = new Dialog();
        // Create the layout for the signUpForm, passing in the Dialog and selected Event
        VerticalLayout signUpFormLayout = createSignUpFormLayout(signUpForm);
        // Add the created layout to the signUpForm
        signUpForm.add(signUpFormLayout);
        // Only the signUpForm can be interacted with when it appears on the screen
        signUpForm.setModal(true);

        Button signUpButton = new Button("Sign Up");
        signUpButton.addClickListener(e -> signUpForm.open());
        return signUpButton;
    }

    private VerticalLayout createSignUpFormLayout(Dialog signUpForm) {
        signUpForm.getElement().setAttribute("aria-label", "Registration Form");

        TextField firstName = new TextField("First Name");
        TextField lastName = new TextField("Last Name");

        H2 headline = new H2("Registration Form");
        headline.getStyle().set("margin-top", "0");

        Button cancel = new Button("Cancel", e -> signUpForm.close());
        Button submit = new Button("Submit", e -> {
            if(fillChecker(firstName.getValue(), lastName.getValue()) == true) {
                String fn = firstName.getValue();
                String ln = lastName.getValue();
                User guest = new User(false, fn, ln,
                    "null", "null", Role.GUEST);

                Set<Events> selected = grid.getSelectedItems();
                Events[] curEvent = selected.toArray(new Events[1]);
                Events selectedEvent = curEvent[0];

                if(selectedEvent == null) {
                    Notification.show("No Event Selected!", 5000, Position.TOP_CENTER);
                } else {
                    userRepository.save(guest); // Saves guest sign-up info to user repository
                    selectedEvent.addUser(fn + " " + ln);
                    selectedEvent.decreaseCapacity(1); // Decrease events participants count by 1
                    
                    // ISSUE HERE
                    // Currently saves new version of event instead of merging
                    UUID toDelete = selectedEvent.getId();
                    eventsRepository.save(selectedEvent);
                    eventsRepository.deleteById(toDelete);

                    signUpForm.close();

                    Notification.show("Registered 1 Guest", 5000, Position.TOP_CENTER);
                }                
            } else {
                Notification.show("Please complete the form to register", 5000, Position.TOP_CENTER);
            }
        });

        submit.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        HorizontalLayout buttonLayout = new HorizontalLayout(cancel, submit);
        buttonLayout.setAlignItems(Alignment.END);
        buttonLayout.getStyle().set("margin-top", "var(--lumo-space-m");
        VerticalLayout signUpFormLayout = new VerticalLayout(headline, firstName, lastName, buttonLayout);
        signUpFormLayout.setPadding(false);
        signUpFormLayout.setSpacing(false);
        signUpFormLayout.setAlignItems(Alignment.STRETCH);
        signUpFormLayout.getStyle().set("width", "18rem").set("max-width", "100%");

        return signUpFormLayout;
    }

    private boolean fillChecker(String firstName, String lastName) {
        if(firstName.equals("") || lastName.equals("")) {
            return false;
        }
        return true;
    }

    private void createIdColumn() {
        idColumn = grid.addColumn(Events::getId, "id").setHeader("ID").setAutoWidth(true);
    }

    private void createNameColumn() {
        nameColumn = grid.addColumn(Events::getName, "name").setHeader("Name").setAutoWidth(true);
    }

    private void createStartDateColumn() {
        startDateColumn = grid.addColumn(Events::getStartDate, "startDate").setHeader("Start Date").setAutoWidth(true);
    }

    private void createEndDateColumn() {
        startDateColumn = grid.addColumn(Events::getEndDate, "endDate").setHeader("End Date").setAutoWidth(true);
    }

    private void createStartTimeColumn() {
        startTimeColumn = grid.addColumn(Events::getStartTime, "startTime").setHeader("Start Time").setAutoWidth(true);
    }

    private void createEndTimeColumn() {
        startDateColumn = grid.addColumn(Events::getEndTime, "endTime").setHeader("End Time").setAutoWidth(true);
    }

    private void createRecurringColumn() {
        recurringColumn = grid.addColumn(Events::getRecurring, "recurring").setHeader("Recurring?").setAutoWidth(true);
    }

    private void createParticipantsColumn() {
        participantsColumn = grid.addColumn(Events::getParticipants, "participants").setHeader("Capacity").setAutoWidth(true);
    }

    private void createPriceColumn() {
        priceColumn = grid.addColumn(Events::getNonMemberPrice, "price").setHeader("Price").setAutoWidth(true);
    }

    private void createLocationColumn() {
        locationColumn = grid.addColumn(Events::getLocation, "location").setHeader("Location").setAutoWidth(true);
    }

    private void createDescriptionColumn() {
        descriptionColumn = grid.addColumn(Events::getDescription, "description").setHeader("Description").setAutoWidth(true);
    }

    private List<Events> getEvents() {
        List<Events> list = eventsService.findAllEvents();
        List<Events> toReturn = new ArrayList<Events>();
        Events e;
        int size = list.size();
        for(int i = 0; i < size; i++) {
            Events temp = list.get(i);
            e = createEvents(temp.getName(), temp.getStartDate(), temp.getEndDate(), temp.getStartTime(), temp.getEndTime(),
                temp.getRecurring(), temp.getParticipants(), temp.getNonMemberPrice(), temp.getLocation(), temp.getDescription());
            toReturn.add(e);
        }
        return toReturn;
    }

    private Events createEvents(String name, java.time.LocalDate startDate, java.time.LocalDate endDate, 
        java.time.LocalTime startTime, java.time.LocalTime endTime, String recurring, int participants, 
            String price, String location, String description) {

        Events e = new Events();
        e.setName(name);
        e.setStartDate(startDate);
        e.setEndDate(endDate);
        e.setStartTime(startTime);
        e.setEndTime(endTime);
        e.setRecurring(recurring);
        e.setParticipants(participants);
        e.setNonMemberPrice(price);
        e.setLocation(location);
        e.setDescription(description);

        return e;

    }
};

Here is my AbstractEntity class:

import java.util.UUID;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class AbstractEntity {

    @Id
    @GeneratedValue
    private UUID id;

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        if (id != null) {
            return id.hashCode();
        }
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof AbstractEntity)) {
            return false; // null or other class
        }
        AbstractEntity other = (AbstractEntity) obj;

        if (id != null) {
            return id.equals(other.id);
        }
        return super.equals(other);
    }
}

Results of adding an Id Column to the sign up grid:
enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尐籹人 2025-01-24 11:53:35

抽象性包含什么?我猜想您缺少有关事件的唯一标识符上的@ID注释,或者在将实体保存到数据库之前没有映射并丢失。没有ID JPA,就无法知道这是一个更新的实体,而不是新的实体。

调试代码并检查该实体是否在此行中包含正确的ID:

eventsRepository.save(selectedEvent)

What does AbstractEntity contain? I'm guessing that your are missing the @Id annotation on your unique identifier for events, or that it is not mapped and goes missing before the entity is saved to the database. Without the id JPA has no way of knowing that this is an updated entity instead of a new one.

Debug the code and check that the entity contains the right ID at this line:

eventsRepository.save(selectedEvent)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文