skip to Main Content

I am working on a Spring Boot app using Jpa and postgresql. It is a booking app that will notify the parties for coming bookings.

I will have 3 user types: Admin, Customer and Employee. enter image description here

I add @OneToOne relation beween User and Customer(Admin and Employee) to have shared PK(Customer PK is FK(User))

@Entity
@Table(name = "userTbl", uniqueConstraints = {@UniqueConstraint(columnNames = "emailAddress")})
public class User {
 @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long IID;
@NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;
....
@OneToOne(mappedBy = "user")
    @JsonBackReference
    private Admin admin;

    @OneToOne()
    @JsonBackReference
    private Customer customer;

    @OneToOne(mappedBy = "user")
    @JsonBackReference
    private Employee employee;
@Entity
@Table(name = "customer")
public class Customer{

    @Id
    @Column(name = "USER_ID")
    private Long IID;

    @OneToOne()
    @MapsId
    private User user;
    private String paymentID;
    private String invoice;

same entity classes for admin and employee

When I try to register a new User, I got ‘attempted to assign id from null one-to-one property [com.application.model.Customer.user]. error.

@Service
public class RegisterAuthenticationService {
    private final AuthenticationManager authenticationManager;
    private final UserRepository userRepository;
    private final CustomerRepository customerRepository;
    private final PasswordEncoder passwordEncoder;
    private final JWTService jwtService;


    public RegisterAuthenticationService(AuthenticationManager authenticationManager,
                                         UserRepository userRepository,
                                         CustomerRepository customerRepository,
                                         PasswordEncoder passwordEncoder,
                                         JWTService jwtService) {
        this.authenticationManager = authenticationManager;
        this.userRepository = userRepository;
        this.customerRepository = customerRepository;
        this.passwordEncoder = passwordEncoder;
        this.jwtService = jwtService;
    }

    @Transactional
    public ResponseEntity<?> registerNewCustomer(UserRegisterRequest registerRequest) {
        if (userRepository.existsByEmailAddress(registerRequest.getEmail())) {
            return ResponseEntity.badRequest().body("Email used");
        }

        String type = registerRequest.getType();

        if (type == null
                || !(type.toUpperCase(Locale.ROOT).equals("ADMIN")
                || type.toUpperCase(Locale.ROOT).equals("CUSTOMER")
                || type.toUpperCase(Locale.ROOT).equals("EMPLOYEE"))) {
            throw new RuntimeException("Invalid role");
        }
        // TODO: add more sanity check (email, password etc...)
        User user = new User(null, registerRequest.getFirstName(),
                registerRequest.getLastName(),
                registerRequest.getEmail(),
                registerRequest.getPhoneNumber(),
                UserStatus.PENDING,
                UserType.valueOf(registerRequest.getType()),
                registerRequest.getGeographicAddress(),
                new Date().toString(),
                null,
                passwordEncoder.encode(registerRequest.getPassword()));
        userRepository.save(user);
        // is it saved, need to be updated refresh
        Long iid = userRepository.getUserByEmailAddress(registerRequest.getEmail()).getIID();

        switch (registerRequest.getType().toUpperCase(Locale.ROOT)) {
            case "CUSTOMER" -> {
                Customer userCustomer = new Customer(iid);
                customerRepository.save(userCustomer);
            }
            case "EMPLOYEE" -> {
                // save to employeee
            }
            default -> {
                // save to admin
            }
        }

        return ResponseEntity.ok("User registered successfully");
    }
}

Also I have a ManyToMany between Employee and Service and @ManyToOne in Booking (with Customer and employee)

@Entity
@Table(name = "booking")
public class Booking {

    @Id
    @GeneratedValue
    private Long IID;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;

    @ManyToOne
    @JoinColumn(name = "employee_id")
    private Employee employee;

    @ManyToOne
    @JoinColumn(name = "service_id")
    private Service service;

One idea is to have just one table User, add ‘type’ (customer, admin or employee) and userCharacteristics object to it. This userCharacteristics object will contain the specific properties for an user type. But with this in mind, how to define the relationship in Booking (with customer and employee) and between Employee<->Service?

Sum:
How to design User entities so that I can have 3 types of user, have a relationship between them and relationships of user entities with other entities (like Booking with customer and employee)?

2

Answers


  1. Chosen as BEST ANSWER
    User user = new User(null, registerRequest.getFirstName(),
                registerRequest.getLastName(),
                registerRequest.getEmail(),
                registerRequest.getPhoneNumber(),
                UserStatus.PENDING,
                UserType.valueOf(registerRequest.getType()),
                registerRequest.getGeographicAddress(),
                new Date().toString(),
                null,
                passwordEncoder.encode(registerRequest.getPassword()));
        user.setCustomer(null);//ADD THIS
        userRepository.save(user); 
        // is it saved, need to be updated refresh
        Long iid = userRepository.getUserByEmailAddress(registerRequest.getEmail()).getIID();
    
        switch (registerRequest.getType().toUpperCase(Locale.ROOT)) {
            case "CUSTOMER" -> {
                Customer userCustomer = new Customer(iid);
                userCustomer.setUser(user);//ADD THIS
                customerRepository.save(userCustomer);
            }
    

    It is because the User in Customer is null


  2. @GeneratedValue(strategy = GenerationType.AUTO)
    

    it’s because the customer id is null. you have to make it generate automatically for the customer too.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search