JPA Entity with hierachy relationship - sql

I have the following Entity
#Entity
public class Project implements Serializable {
#Id
private Integer project_id;
private String project_name;
other attributes
#OneToOne
#JoinColumn(name = "lead_emp_no", referencedColumnName = "emp_no")
private Employee projectLead;
// but the following two relationships need to be a connect by:
#OneToOne
#JoinColumn(name = "lead_boss_emp_no", referencedColumnName = "emp_no")
private Employee projectLeadBoss;
#OneToOne
#JoinColumn(name = "lead_bosses_boss_emp_no", referencedColumnName = "emp_no")
private Employee projectLeadBossesBoss;
With this setup, we have to manually maintain the employee numbers for the Lead's boss and the Lead's Boss's boss. This relationship is [somewhat] already available knowing the projectLead employee:
The Employee Entity is as follows:
#Entity
public class Employee implements Serializable {
#Id
private Integer emp_no;
private Integer bosses_emp_no;
Is it possible to get my Project entity to connect to the boss and bosses Employee based on projectLead? In single query I'd like to get a table of all projects and their lead's hierarchy. I'm open to entity redesign.

You can replace the bosses_emp_no in Employee should with a more helpful boss:
#Entity
public class Employee implements Serializable {
#Id
private Integer emp_no;
#OneToOne
#JoinColumn(name = "boss_emp_no", referencedColumnName = "emp_no")
private Employee boss;
Then you simply add a couple of delegating methods to Project
public Employee getProjectLeadBoss() {
return this.projectLead.getBoss();
}
public Employee getProjectLeadBossesBoss() {
return this.getProjectLeadBoss().getBoss();
}

Related

Split huge sql table logically into smaller tables

I'm making a Spring boot application with Hibernate ORM framework.
I have Employee entity there:
#Entity
public class Employee {
private String firstName;
private String position;
//// more than 30 private fields
//// fields related to one sublogic
private String category;
private LocalDate categoryAssignmentDate;
private LocalDate categoryAssignmentDeadlineDate;
private LocalDate docsSubmitDeadlineDate;
}
There are more than 30 private fields in Employee class.
And as you can see, I have 4 fields related to same sublogic Category.
So my question is: Is it a good practise to split my Employee entity into two entities Employee and Category, which will be connected as OnetoOne relationship?
Does it make the code clearer?
Use embedded and embeddable to prevent double table mapping and unnecessary OneToOne relations.
#Entity
public class Employee {
private String firstName;
private String position;
#Embedded
private Category category
}
#Embeddable
public class Category{
private String category;
private LocalDate categoryAssignmentDate;
private LocalDate categoryAssignmentDeadlineDate;
private LocalDate docsSubmitDeadlineDate;
}
You might need to add attribute overrides

Design optaplanner constraints of booking system

I would like to design a booking system using optaplanner, bellow my business model:
Customers (id, name) //Customer table
Services(id, name, description, duration) //services that a customer can book, duration can be 15min, 30min, ..., N x 15min
Employees(id, name) //Employee tables
Appointment(id, customerId, employeeId, serviceId, startTime, endTime)
To book an appointment, the customer will select:
The day of the appointment (mandatory)
A list of services (mandatory)
A list of employees (optional)
I would like to know I can design the model to return the list of availability for a given day, given list of services.
Bellow a basic pseudo-code model :
#Entity
public class Service extends PanacheEntityBase {
#Id
#GeneratedValue
#NotNull
private Long id;
#NotBlank
private String name;
private int durationInGrains;
}
public class TimeGrain {
public static final int GRAIN_LENGTH_IN_MINUTES = 15;
private int grainIndex; // unique
private int startingMinuteOfDay;
}
#Entity
public class Employee extends PanacheEntityBase {
#PlanningId
#Id
#GeneratedValue
#NotNull
private Long id;
#NotBlank
private String name;
}
#Entity
public class Appointment extends PanacheEntityBase {
#Id
#GeneratedValue
#NotNull
private Long id;
private Employee employee;
private Service service;
private LocalDateTime startTime;
private LocalDateTime endTime;
}
#PlanningEntity
public class Availability {
#PlanningVariable(valueRangeProviderRefs = { "timeGrainRange" })
private TimeGrain startingTimeGrain;
#PlanningVariable(valueRangeProviderRefs = "providerRange")
private Provider provider;
private Service service;
}
#PlanningSolution
public class AppointmentAvailability {
#ValueRangeProvider(id = "timeGrainRange")
#ProblemFactCollectionProperty
private List<TimeGrain> timeGrainList;
#ProblemFactCollectionProperty
#ValueRangeProvider(id = "providerRange")
private List<Provider> providerList;
#ProblemFactCollectionProperty
#ValueRangeProvider(id = "appointmentsRange")
private List<Appointment> appointmentList;
#PlanningEntityCollectionProperty
private List<Availability> availabilityList;
#PlanningScore
private HardMediumSoftScore score;
}
As I am new to optaplanner, could you please advise if this is the way to go?
UPDATE 1: I have simplified the problem to the minimum for design purposes.
Take a look at the meeting scheduling example in optaplanner-examples, to get inspired on how to model it. Also see the Time Grain pattern in the docs in the section Design Patterns. The school timetabling quickstart follows the Timeslot pattern instead.

how to get entities with many to may dependency

This is project entity which I need to get by current user Id:
#Entity
#Table(name = "project")
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany
#JoinTable(name = "project_user",
joinColumns = #JoinColumn(name="projects_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="users_id", referencedColumnName="id"))
private Set<User> users = new HashSet<>();
}
this is user entity whichs Id I'll use to get products:
#Entity
#Table(name = "jhi_user")
public class User extends AbstractAuditingEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(mappedBy = "users")
private Set<Project> projects = new HashSet<>();
}
Repositories classes extend JpaRepository class. How I can get all projects for current user Id?
Native SQL statement that I can use is:
SELECT * FROM project WHERE id IN (SELECT projects_id FROM project_user WHERE users_id = ?);
It should be as simple as this...
User user = userRepository.findById(100L);
Set<Projects> projects = user.getProjects();
Because of your mapping, JPA takes care of the rest.

Glassfish says incomplete JoinColumns

I used composit keys but I changed my mind and removed this kind of keys in my web application in NetBeans. But Glassfish says : the module has not been deployed, because of the invalid JoinColumns contents.
Exception Description: The #JoinColumns on the annotated element [field client] from the entity class [class x.ClientOrder] is incomplete. When the source entity class uses a composite primary key, a #JoinColumn must be specified for each join column using the #JoinColumns. Both the name and the referencedColumnName elements must be specified in each such #JoinColumn.
I have removed all of the tables from the DB, restarted the container, called the "Clean and Build" command to the project (it is succeed). But the EJB deployment fails. What should I do for the container forget the past?
The source code of entities:
#Entity
#Getter
#Setter
#Inheritance( strategy = InheritanceType.JOINED )
#DiscriminatorColumn( name = "roleType", discriminatorType = DiscriminatorType.STRING, length = 10 )
#NamedQuery( name=UserRole.QUERYNAME_GET_ROLE_BY_USERID_AND_TYPE, query = "SELECT ur FROM UserRole ur WHERE ur.userWR.id = :userID AND ur.roleType = :roleType" )
abstract public class UserRole implements Serializable
{
private static final long serialVersionUID = 1L;
public static final String QUERYNAME_GET_ROLE_BY_USERID_AND_TYPE = "userRole_getRoleByUserIDAndType";
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private int id;
#Column
private String roleType;
#Id
#ManyToOne
#JoinColumn( name="user_id", referencedColumnName = "id" )
private UserWithRoles userWR;
}
#Entity
#Data
#NamedQuery( name = Client.QUERYNAME_GET_ALL_CLIENTS, query="SELECT c FROM Client c" )
public abstract class Client extends UserRole
{
public static final String QUERYNAME_GET_ALL_CLIENTS = "client_GetAllClients";
}
#Entity
#Data
#NamedQuery( name=ClientOrder.QUERYNAME_GET_CLIENT_ORDERS, query = "SELECT co FROM ClientOrder co WHERE co.client = :userID" )
public class ClientOrder implements Serializable
{
private static final long serialVersionUID = 1L;
public static final String QUERYNAME_GET_CLIENT_ORDERS = "clientOrders_getClientOrders";
#Id
#GeneratedValue( strategy = GenerationType.AUTO )
private int id;
private String name;
#ManyToOne
#JoinColumn( name = "client_id", referencedColumnName = "id" )
private Client client;
#OneToMany( mappedBy = "clientOrder" )
private List<ClientOrderItem> orderItems;
}
OK. There was an error in the UserRole table. I have forgotten to remove the second #Id annotation on the userWR field. After I have removed it and rebuilt the app it deploys again.

JPA mapping #OneToOne own class

Hello guys I have a problem mapping the typeOneToOne to its class. I have a Person class that a person is married and has an affair with the Same Person class but it is his wife. The foreign key is the name and surname.
#Table(name="PERSON")
public class Person implements Serializable{
#PrimaryKeyJoinColumns({#PrimaryKeyJoinColumn(name="coniuge",referencedColumnName="NAME"),#PrimaryKeyJoinColumn(name="coniuge",referencedColumnName="SURNAME")})
private Person coniuge = null;
#Id
#Column(name="NAME",nullable=false)
private String name;
#Id
#Column(name="SURNAME",nullable=false)
private String surname;
public Person getConiuge() {
return coniuge;}
The manager sevice:
public void aggiungiConiuge(Person coniugeA, Person coniugeB){
manager.getTransaction().begin();
Person cA = manager.find(Person.class, coniugeA);
Person cB = manager.find(Person.class, coniugeB);
cA.setConiuge(cB);
cB.setConiuge(cA);
manager.merge(cA);
manager.getTransaction().commit();
}
how can I solve the problem ?? On DB does not create the two columns (foreign key) with keys Primare's partner (name and surname)
As forename/surname is not guaranteed to be unique use a surrogate key and map as below:
#Table(name = "PERSON")
public class Person implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO) //or some other strategy
private Long id;
#OneToOne()
#JoinColumn(name = "coniuge_id")
private Person coniuge;
#Column(name = "NAME", nullable = false)
private String name;
#Column(name = "SURNAME", nullable = false)
private String surname;
public void setConiuge(Person coniuge) {
this.coniuge = coniuge;
coniuge.coniuge = this;
}
}
Two problems. 1, you are using PrimaryKeyJoinColumns instead of JoinColumns. 2, you specified a single "coniuge" field to be used as a foriegn key to referenced Person's Name and Surname fields. You need to specify a field for each.
Try:
#OneToOne
#JoinColumns({#JoinColumn(name="CONIUGE_NAME", referencedColumnName="NAME"),
#JoinColumn(name="CONIUGE_SURNAME", referencedColumnName="SURNAME")})
private Person coniuge;
This will allow you to keep using your current composite primary key. Alan's solution below to generate a unique id field should be used instead where it can though.