Hibernate LazyLoading initialization of List - sql

I've typical User and Comment-Models. One user has more comments.
On one usecase i want to get only a user from db, without comments.
I thought, as soon i tell "getComments()", so only in this moment, my List will initialized with
something like "select comment from Comment c where c.userId = 1" from Hibernate.
But my List of comments will be initialized everytime when i say findyById or "select user from User".
#Entity
#Getter #Setter
#ToString(exclude = {"comments")
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class User implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Builder.Default
#OneToMany(mappedBy="user", fetch = FetchType.LAZY)
private List<Comment> comments = new ArrayList<>();
}
My Comment Model:
#Entity
#Getter #Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Comment implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Builder.Default
#ManyToOne(fetch = FetchType.LAZY)
private User user; }
UserRepository:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("SELECT user FROM User user WHERE user.id =:id")
Optional<User> findUserById(#Param("id") long id); }
When i tell:
userRepository.findUserById(1);
So i see at first only one select-statment for user.
Few seconds later i see next statment for comment, but i did not tell "user.getComments()"
So how can i get User-Model without any Lazy-List's with related Object?

Related

Deadlock when we we have dependent entities in hibernate and try to update table using multiple threads in Vertica

I have two java classes. Father.java and Children.java
#Entity
#Table(name = "FATHER")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
class Father implements Cloneable
{
#Id
#Column(name = "father_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long fatherId;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "father_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<Children> children = new ArrayList<Children>();
//getter and setters and public constructors
}
#Entity
#Table(name = "Children")
class Children implements Comparable<Children>
{
#JsonIgnore
#Id
#Column(name = "children_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long child_id;
#JsonIgnore
#Column(name = "father_id")
private long fatherId;
//public constructors and getters and setters
}
public interface RelationDao{
public Father update() throws Exception;
}
#Repository("relationDao")
#EnableTransactionManagement
#Transactional
public RelationDaoImpl{
#Override
#Transactional("txManager")
public Father update(Father father)
{
father = merge(father);
//added retry logic as well also father is updated with a new child which is why merge
}
}
I receive the Deadlock X exception if several threads visit the same table (entity father) to updates with distinct row entries, even though the records are different.
Is there any way to fix why the entire table locks up instead than just one row?
Even though I haven't updated or added anything to the code, the transaction isolation level is SERIALIZABLE.
DB system is Vertica
Explained here, if anyone is coming here to check why Vertica doesn’t support row level locks for updates or delete. https://stackoverflow.com/a/69917383/8799862
So I used synchronized to perform thread-safe updates and deletes.

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.

What is a correct way of designing REST API's for SpringBoot

As I know about designing of REST-API's in SpringBoot we will design API's for User like
For ADD User = /v1/users (Add a single object into a user collection)
For GET/UPDATE/DELETE user = /v1/users/{userId} (for get/update/delete
a single object from users collection)
Now We also design an API's for User Address like
For Add Address = /v1/users/{userId}/addresses (Add a single object
into addresses of user followed by userId)
For GET/UPDATE/DELETE = /v1/users/{userId}/addresses/{addressId}
(get/update /delete of address from addresses for a user of given
userId)
So, I have created API's like this but for add/get/update/delete I can direct addresses into Address table via RestController -> Services -> Repository -> DB
Now for Address CRUD I'm never used {userId} which is provided in API
Sample for Add/Update address
#Override
public Address addAddress(Address address) {
address = addressRepository.save(address);
return address;
}
Is there I'm doing something wrong in code or my concept about rest is not cleared.
Thank you in advance.
I think first you should come up with the structure of relationship between user and address.
Like ADDRESS CANT EXISTS WITHOUT USER and USER CAN HAVE MANY ADDRESSES or CAN HAVE ONLY ONE ADDRESS that is basically the cardinality of the relationship.
See the accepted anwer.
Once that done and you come up with the CASCADE TYPE and USE THE HELPER method persist the parent along with child.
Here is the good example.
Will try to upload code for your example.
Let me know of this:)
EDIT:
#Entity
#Getter
#Setter
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class User {
private Long id;
private String userName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address) {
addresses.add(address);
address.setUser(this);
}
public void removeAddress(Address address) {
address.setUser(null);
this.addresses.remove(address);
}
}
#Entity
#Getter
#Setter
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class Address {
private Long id;
private String address;
#ManyToOne
private User user;
}
public class Service
{
#PostMapping(value="/saveAddressForUser")
public void saveAddressForUser(#RequestBody AddressForUser address)
{
User user=getUserFromDatabase(userId);
user.addAddress(address);
Repository.persist(user);//it will also persist address as cascade type is all.
}
}

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.