Hibernate 4 and Postgres : How to create a sequence per table? - sql

I use Hibernate 4 to use mapping to a Postgres database. Before doing mapping i create first java entities. And then, i use a java class to generate sql script from my entities. Here is my entities :
User entity
#Entity
#Table(name="myusers")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="fistname")
private String firstName;
#Column(name="lastName")
private String lastName;
....
}
Project entity
#Entity
#Table(name="projects")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="title")
private String title;
#Column(name="description")
private String description;
..
}
I've noticed that #GeneratedValue(strategy = GenerationType.AUTO) produces the same sequence for table myusers and projects. If i create the first record on myusers table the id will have "1" as value and then when i create the first record in table projects, this record will have id =2. They use both the same sequence.
I want to know how i cannot modify my entities to specify to Hibernate to create a sequence for each table.

If you're on a recent Hibernate, try:
#GeneratedValue(strategy = GenerationType.IDENTITY)
If it still uses a sequence per table use:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="mytable_id_seq")
#SequenceGenerator(name="mytable_id_seq", sequenceName="mytable_id_seq", allocationSize=1)
See hibernate could not get next sequence value

Related

How to create Entity class with composite kays (Kotlin, Spring boot)

I have a database diagram, which i need to implement in Entity classes
Diagram image
User entity:
#Entity
class User (
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val idUser: Int = -1,
#Column(unique=true)
val name: String = "",
#Column(unique=true)
val email: String = "",
#Column(nullable = false)
val password: String = ""
)
Post entity:
User entity:
#Entity
data class Post (
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val idPost: Int = -1,
#Column(nullable = false)
val title: String = "",
#Column(nullable = false)
val body: String = "",
#Column(nullable = false)
val date: String = Date().toString()
)
I just don't understand how to organize a relationship between tables.
Also IDEA reports an error when a table does not have Primary Key.
Help me with implementation of UserPost Entity class.
SOLVE
Okay, I have a solution, just add a data source (I used MySQL) and use Generate Kotlin Entities.kts then IDEA will automatically create all Entity classes. I think it is the most easy way.
You can define your entities as below with required details such as #columns on attributes and other details.
The below classes are just for reference and to guide on the path.
Please read more about Composite keys and refer the link https://www.baeldung.com/jpa-composite-primary-keys
#Entity
#IdClass(UserPost.class)
public class Post {
#Id
private int idPost;
#Id
private int idUser;
private String title;
private String body;
private LocalDateTime date;
}
#Entity
#IdClass(UserPost.class)
class User{
#Id
private int idPost;
#Id
private int idUser;
private String name;
private String email;
private String password;
}
class UserPost implements Serializable {
private static final long serialVersionUID = 1L;
private int idPost;
private int idUser;
//No-Args constructor and All-Args constructor
//hashcode
//equals
}
Its in java, In kotlin there will not be much diffrence. There is another way to implement the composite key using #Embeddable and #EmbeddableID

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.

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.