How to create Spring Entity and Repository without primary key - java

I have a table with two columns user_id and role_id. There's no unique column in table and I can't add one. How can I create Entity and Repository in Spring without a primary key?
This is my UserRole.class
public class UserRole {
#Column(name = "user_id")
private int userId;
#Column(name = "role_id")
private int roleId;
//getters and setters
}
But with this class i get the following error:
nested exception is org.hibernate.AnnotationException: No identifier specified for entity:
I saw that one of the answers is to use all of the columns as the id, but i have no idea how to do it.

Please see the awnser in this post. This should help you.
PK Explained
Another Option is if this is a join table, than you could make Embeded PK
#Embeddable
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder(toBuilder = true)
public class PersonGroupPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(insertable=false,unique = false, updatable=false, nullable=false)
private Long personId;
#Column(insertable=false, unique = false,updatable=false, nullable=false)
private Long groupId;
}

Related

Hibernate One To One mapping, Foreign Key is NULL

This is my first attempt to map with One to One relation. I have the following entities:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Size(max = 100)
private String name;
#Email(message = "Email should be valid")
private String email;
#OneToOne
#PrimaryKeyJoinColumn
private Key key;
}
AND
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Key {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private UUID number;
#OneToOne
private Client client;
public Key(UUID number) {
this.number = number;
}
}
They do not see each other, I get NULL in the foreign key section. There is a solution when using the EntityManager class in the following post:
JPA / Hibernate OneToOne Null in foreign key
Unfortunately, that method doesn't work for me.
Database snapshot:
Thank you for the answers!
We don't need to mention the #PrimaryKeyJoinColumn annotation. When we are mapping the tables it will create primary key and foreign key. We just need to map properly.
In the Client model class you have to create the mapping like below
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "key_id", referencedColumnName = "id")
private Key key;
and in the Key model class like this
#OneToOne(mappedBy = "key")
private Client client;

JPA one to one mapping creates multiple query when child entity is not found

I have a parent entity 'contracts' that has a one-to-one relation with another entity 'child-contract'. the interesting thing is that the mapping field ('contract_number')id not a primary key-foreign key but is rather a unique field in both the tables. Also it is possible for a contracts to not have any child contract altogether. With this configuration I have observed hibernate to generate 1 additional query every time a contracts does not have a child-contract. I filed this behavior very strange. Is there a way to stop these unnecessary query generation or have I got something wrong.
below is a piece of my code configuration.
#Data
#Entity
#Table(name = "contracts")
public class Contracts implements Serializable {
#Id
#JsonIgnore
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
#OneToOne(fetch=FetchType.EAGER)
#Fetch(FetchMode.JOIN)
#JsonProperty("crm_contracts")
#JoinColumn(name = "contract_number", referencedColumnName = "contract_number")
private ChildContract childContract ;
}
#Data
#NoArgsConstructor
#Entity
#Table(name = "child_contract")
#BatchSize(size=1000)
public class ChildContract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty("id")
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
}
Please help.
Thank-you
You can use NamedEntityGraph to solve multiple query problem.
#NamedEntityGraph(name = "graph.Contracts.CRMContracts", attributeNodes = {
#NamedAttributeNode(value = "crmContract") })
Use this on your repository method as
#EntityGraph(value = "graph.Contracts.CRMContracts", type = EntityGraphType.FETCH)
// Your repo method in repository

How to create a 1:n relationship with hibernate?

I am using hibernate to represent a database with the three major Entities User, Project and Comment. User and Project inherit from Base class. The Project also holds an unlimited amount of comments.
In the POJO i tried to represent the collection of comments associated by a project by with a List<Comment>.
My major problem is, when i i go and take a project which holds a number of comment references within the list java will throw an IllegalArgumentException saying, that it cant access the id field of comment, as it only gets an ArrayList.
Caused by: java.lang.IllegalArgumentException: Can not set int field com.project.objects.Comment.id to java.util.ArrayList
My classes are as followed - without Constructor/Setter/Getter as these are plain simple:
#MappedSuperclass
public abstract class Base {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String name;
#Column
private String longDesc;
#Column
private String briefDesc;
#Column
#ElementCollection(targetClass=String.class)
private List<String> goals;
#Column
private String picture;
#Column
private int cType;
#Entity(name = "Project")
#Table(name = "project")
public class Project extends Base {
#Column
private String start;
#Column
private String end;
#Column
private String manager;
#ElementCollection(targetClass=Comment.class)
#ManyToOne(targetEntity = Comment.class, fetch = FetchType.EAGER)
#JoinColumn(name = "comment_id")
private List<Comment> comments;
#Entity(name = "Comment")
#Table(name = "comment")
public class Comment {
#Id
#Column(name="comment_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String comment;
#Column
private int rating;
#Column
private int pcuser;
#Column
private int cType;
Your 1:N association is wrong, as it is actually a N:1 right now. The correct would be:
Entity(name = "Project")
#Table(name = "project")
public class Project extends Base {
#Column
private String start;
#Column
private String end;
#Column
private String manager;
#OneToMany(mappedBy = "project", fetch = FetchType.EAGER)
private List<Comment> comments;
And in your Comment class:
#Entity(name = "Comment")
#Table(name = "comment")
public class Comment {
#Id
#Column(name="comment_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String comment;
#Column
private int rating;
#Column
private int pcuser;
#Column
private int cType;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_project", nullable = false)
private Project project;
// THIS is the required and obrigatory mapping that you forgot.
// It's the foreing key itself
Disclaimer
I've never actually used Hibernate with inheritance before (usually, it's desnecessarily complex and also inefficient for a relational database) but check `https://www.baeldung.com/hibernate-inheritance` and `https://marcin-chwedczuk.github.io/mapping-inheritance-in-hibernate` for more information.
You're using a #ManyToOne annotation for comments but it should be #OneToMany.
In order to use #OneToMany you would have to have a column called something like project_id in the comment table, which you would reference from the #OneToMany field. Do you have that?
If not, how are you linking comments to projects in your database?
By the way, it's really easy to create poorly-performing systems with Hibernate, because it tends to obscure the cost of hitting the database. You've said that there can be any number of comments associated with a project. Do you really want to load them all every time the code loads a project? Let's say you just want a list of projects, for example to populate a selection list. Simply loading that list will also load every comment in the system, even though you don't actually need them.
Comment is an entity and should not be used with the #ElementCollection inside the Project entity.
Your relationship is a project to many comments. #OneToMany

How to define the association table as pojo entity

I have 3 tables in the db. I am trying to write the JPA entities. I am facing some issues with Association table entity. My entities are as follows,
Person.java
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
//setter and getter
}
Exam.java
#Entity
#Table(name = "exam")
public class Exam {
#Id
#GeneratedValue
private long examId;
#Column(nullable = false)
private String examName;
#Column(nullable = false)
private int marks;
//Setters and getters
}
The table structure for association table is,
create table person_exam (
personId BIGINT not null,
examId BIGINT not null,
primary key (personId, examId)
);
I tried the association table entity with #ManyToMany annotation for both the properties which is not giving me the result.
Can anyone please suggest me what should I need to use (ManyToMany/OneToOne/ManyToOne/OneToMany ) in my entity for the above person_exam table.
from the PRO JPA 2nd Ed. book:
the only way to implement a many-to-many relationship is with a separate join table. The consequence of not having any join columns in either of the entity tables is that there is no way to determine which side is the owner of the relationship. Because every bidirectional relationship has to have both an owning side and an inverse side, we must pick one of the two entities to be the owner.
So I chose the the Person entity. Applying the needed changes to your incomplete code:
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
/**
* we need to add some additional metadata to the Person designated
* as the owner of the relationship, also you must fully specify the names of
* the join table and its columns because you already provided a schema
* for the association table, otherwise the JPA provider would generate one.
*/
#ManyToMany
#JoinTable(name="person_exam",
joinColumns=#JoinColumn(name="personId"),
inverseJoinColumns=#JoinColumn(name="examId"))
private Collection<Exams> exams;
//setter and getter
}
#Entity
#Table(name = "exam")
public class Exam {
#Id
#GeneratedValue
private long examId;
#Column(nullable = false)
private String examName;
#Column(nullable = false)
private int marks;
//Setters and getters
/**
* As in every other bidirectional relationship,
* the inverse side must use the mappedBy element to identify
* the owning attribute.
*/
#ManyToMany(mappedBy="exams")
private Collection<Person> people;
}

Composite keys with Hibernate

I need help to create the correct pojo's from this database...
https://www.dropbox.com/s/j2lfu44zpqfcxb4/dbr.PNG
I have tried creating this classes...
#Entity
#Table(name="Municipio", catalog="elecciones2014", schema="")
public class Municipio implements Serializable{
#EmbeddedId
private MunicipioPk idMunicipio;
#Basic(optional=false)
#Column(name="nomb_municipio")
private String nomb_municipio;
}
With this Embedded class
#Embeddable
class MunicipioPk implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name="id_depto")
String departamento;
#Column(name="id_municipio")
String idMunicipio;
}
The problem is when i want to reference to 'Municipio' from 'JRV' y don't know how to access to field 'id_municipio'. I had this code but it doesn't work
#Entity
#Table(name = "JRV", catalog = "elecciones2014", schema = "")
public class Jrv {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_jrv")
private int id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="id_municipio",referencedColumnName="idMunicipio")
private Municipio municipio;
#ManyToOne
#JoinColumn(name="DUI",referencedColumnName="dui")
private PadronElectoral dui;
}
can someone help me?
how I have to do it?
Thanks in advice!!
Here you are defining single join column, but the Municipio entity's PK has two columns. Also the referencedColumnName should be the name of the column not the entity's property.
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="id_municipio",referencedColumnName="idMunicipio")
private Municipio municipio;
So you could do something like this:
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="id_municipio", referencedColumnName="id_municipio"),
#JoinColumn(name="id_depto", referencedColumnName="id_depto")
})
private Municipio municipio;
Which translates to this SQL (I got this by generating SQL schema from your entities after the modification mentioned above):
create table elecciones2014.JRV (
id_jrv serial not null,
id_depto varchar(255),
id_municipio varchar(255),
primary key (id_jrv)
);
alter table elecciones2014.JRV
add constraint FK_7scd8alu3nf4tsyh3hq2ryrja
foreign key (id_depto, id_municipio)
references elecciones2014.Municipio;

Categories