Map primary key composed of two foreign keys? hibernate - java

I have 3 classes Player(PK Id_player), Match(PK Id_match) and Inscription(PK should be Id_player and Id_match). A Player has ONE and ONLY ONE inscription(1 Player-> 1 Inscription), and a Match can be in many inscriptions(1 Match -> Many inscriptcions). So the table Inscriptions have 2 foreig keys Id_player and Id_match, the problem is that I don't how to tell hibernate that both foreing keys must be a composed primarey key for Inscriptions Table. This is my code::
#Entity
#Table(name = "Players")
public class Player{
#Id #GeneratedValue
private Long Id_player;
#OneToOne
#JoinColumn(name = "payer_id")
Inscription Inscription;}
#Entity
#Table(name="Matches")
public class Match{
#Id #GeneratedValue
private long Id_match;
#OneToMany
#JoinColumn(name = "id_match")
List<Inscription> inscriptions= new ArrayList<>();
What should I write on Inscription class to make both Fk's a composed PK. Thanks

Check this :
Player
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "Players")
public class Player {
#Id
#GeneratedValue
private Long Id_player;
#OneToOne
private Match match;
}
Match
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="Matches")
public class Match{
#Id #GeneratedValue
private long Id_match;
#OneToMany
#JoinTable(name="Inscription",
joinColumns=#JoinColumn(name="MATCH_ID"),
inverseJoinColumns=#JoinColumn(name="PLAYER_ID"))
private List<Player> playersList;
public long getId_match() {
return Id_match;
}
public void setId_match(long id_match) {
Id_match = id_match;
}
public List<Player> getPlayersList() {
return playersList;
}
public void setPlayersList(List<Player> playersList) {
this.playersList = playersList;
}
}

Related

JPA Spring repository findAll() returns an empty List

I am trying to fetch all the records using JPA findAll. If I run the same query in the terminal, I get some rows as a result, but not through JPA. I tried other answers on stackoverflow, but nothing worked. I tried adding public getters and setters, although which I assume was done by the annotations.
Model class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#ToString
#Entity
#Table(name = "tea")
public class Product {
#Id
#GeneratedValue(generator = "prod_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "prod_seq", sequenceName = "seq_prod", allocationSize = 1, initialValue = 1)
#Column(name = "product_id")
private int productId;
private String name;
#Column(name = "price_per_kg")
private int pricePerKg;
private String type;
#Lob
#Column(length = 2000)
private String description;
#Column(name = "image_url")
private String imageUrl;
private String category;
}
Service class:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.tea.exceptions.ProductNotFoundException;
import com.tea.models.Product;
import com.tea.repository.ProductRepository;
#Service
public class ProductServiceImpl implements ProductService{
#Autowired
ProductRepository productRepository;
#Override
public List<Product> getAll() throws ProductNotFoundException {
return productRepository.findAll();
}
}
Edit: Adding the repository code:
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.tea.models.Product;
public interface ProductRepository extends JpaRepository<Product,Integer >{
#Query("from Product where type like :type ")
List<Product> findByType( String type);
#Query("from Product where type =?2 and category= ?1")
List<Product> findByCategoryAndType(String category, String type);
#Query("from Product where category like :category")
List<Product> findByCategory(String category);
}
I think query should contain alias name for table like Product p and then condition like p.type.

jpa #manytoone creates composite primary key instead of #id

I am running spring jpa project and I have following class containing #ManyToOne relations:
package ba.fit.vms.pojo;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.springframework.format.annotation.DateTimeFormat;
#Entity
#Table(name="korisnik_vozilo")
public class KorisnikVozilo implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#ManyToOne( cascade = {CascadeType.REFRESH}, fetch=FetchType.EAGER )
#JoinColumn(nullable=false, updatable=false)
private Vozilo vozilo;
#ManyToOne( cascade = {CascadeType.REFRESH}, fetch=FetchType.EAGER )
#JoinColumn(nullable=false, updatable=false)
private Korisnik korisnik;
#Column(name = "dodijeljeno")
#DateTimeFormat(pattern = "yyyy-MM-dd")
#NotNull
private Date dodijeljeno;
#Column(name = "vraceno")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date vraceno;
...
}
For some reason, starting the server, this code creates composite primary key (korisnik_id,vozilo_vin), instead of #Id defined primary key. Here is the screenshot of the table:
Can someone explain to me what did I do wrong and how to write this code so I do not get this composite key in the database, but the one defined in the class.
It even sets autoincrement on korisnik_id!
Try getting rid of updatable=false. being unupdatable, the two columns might be be viewed as an immutable identity of the entity.
You may check how you can use #JoinColumn to solve your problem.

Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property

I need to make onetomany relationship but this error appears
mappedBy reference an unknown target entity property
this is parent Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property
package com.dating.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name="question")
public class PsyQuestions {
#Id
#GenericGenerator(name="autoGen" ,strategy="increment")
#GeneratedValue(generator="autoGen")
#Column(name="questionid")
private long psyQuestionId;
#Column(name="questiontext")
private String question;
#OneToMany(fetch = FetchType.LAZY,mappedBy="question")
private List<PsyOptions> productlist=new ArrayList<PsyOptions>();
public PsyQuestions() {
super();
}
public List<PsyOptions> getProductlist() {
return productlist;
}
public void setProductlist(List<PsyOptions> productlist) {
this.productlist = productlist;
}
public long getPsyQuestionId() {
return psyQuestionId;
}
public void setPsyQuestionId(long psyQuestionId) {
this.psyQuestionId = psyQuestionId;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
}
and this child class
package com.dating.model;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name="option")
public class PsyOptions {
#Id
#GenericGenerator(name="autoGen" ,strategy="increment")
#GeneratedValue(generator="autoGen")
#Column(name="optionid")
private long psyOptionId;
#Column(name="optiontext")
private String optionText;
#JoinColumn(name = "questionid")
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
PsyQuestions psyQuestions;
public PsyOptions() {
super();
}
public PsyQuestions getPsyQuestions() {
return psyQuestions;
}
public void setPsyQuestions(PsyQuestions psyQuestions) {
this.psyQuestions = psyQuestions;
}
public long getPsyOptionId() {
return psyOptionId;
}
public void setPsyOptionId(long psyOptionId) {
this.psyOptionId = psyOptionId;
}
public String getOptionText() {
return optionText;
}
public void setOptionText(String optionText) {
this.optionText = optionText;
}
}
You need to set the mappedBy attribute of the #OneToMany annotation to psyQuestions instead of question. The value of mappedBy attributes is the name of the class field on the other side of the relationship, in this case psyQuestions of the ManyToOne side of class PsyOptions.
public class PsyQuestions {
....
#OneToMany(fetch = FetchType.LAZY,mappedBy="psyQuestions")
private List<PsyOptions> productlist=new ArrayList<PsyOptions>();
....
I had the same issue because the mappedBy in the source entity was defined to "enrollment" (annotated with #OneToMany) but the corresponding property in the target entity was "bankEnrollment"; this is the property annotated with #ManyToOne.
After updating from enrollment to bankEnrollmentin the source entity, the exception went away (as expected_.
Lesson learnt: the mappedBy value (e.g. psyQuestions) should exist as a property name in the target entity.
Not sure if this is going to help anyone, it was a simple mistake caused this error on my config. Without realising I have had two different packages containing domain class files. Mapped member was in the other package while the application was only scanning single package path.
It was hard to figure out as they were different only by a single character e.g. org.abc.core.domains and org.abcs.core.domains.
Added other package to database #configuration scanners resolved the issue for me.
I just correct my mapping and it solved the problem.
...
#OneToMany(fetch = FetchType.LAZY,mappedBy="question")
...

Get OrderBy a ManyToOne relation In Hibernate

I Have 2 tables
1.User
2.Company
For each user there is a company. For each company it can multiple users.
UserBean.java
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "tab_user")
public class UserBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "user_id")
private int user_id;
#Column(name="user_login_pwd")
private String user_login_pwd;
#ManyToOne
#JoinColumn(name="comp_id")
private CompanyBean companyBean
And my CompanyBean is
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "tab_company")
public class CompanyBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "comp_id")
private Integer comp_id;
#Column(name = "comp_code")
private String comp_code;
#OneToMany(mappedBy = "companyBean" , fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(value = FetchMode.SUBSELECT)
private List<UserBean> companyUserList;
This is my CompanyBean mapping class.
Now i need to show list of users order by 'comp_code'. My DAO implementation for users list is
#SuppressWarnings("unchecked")
#Override
public List<UserBean> getUserList( String orderBy, String orderField) throws Exception{
List<UserBean> userList = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try{
Criteria crit = session.createCriteria(UserBean.class);
if(orderBy.equals("asc")){
crit.addOrder(Order.asc(orderField));
}else{
crit.addOrder(Order.desc(orderField));
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
userList = crit.list();
}finally{
session.close();
}
return userList;
}
So how can i get order by comp_code of CompanyBean in usersList? Please help.
No Hibernate solution is to create your own Comparator and to order with Collections.sort;
Hibernate solution is using of #OrderBy annotation.
Using hibernate with annotations, i want a one-many relationship to be sorted
By creating alias for beans we can get orderBy from manyToOne field
#SuppressWarnings("unchecked")
#Override
public List<UserBean> getUserList( String orderBy, String orderField) throws Exception{
List<UserBean> userList = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try{
Criteria crit = session.createCriteria(UserBean.class,"user").createAlias("user.companyBean", "company");
/*If my order field is from company bean then it should be company.company_field*/
if(orderBy.equals("asc")){
crit.addOrder(Order.asc(orderField));
}else{
crit.addOrder(Order.desc(orderField));
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
userList = crit.list();
}finally{
session.close();
}
return userList;
}

In Spring Junit test how can I test cascade operation with default rollback=true

This is a my sample test case in which A has One-to-Many relationship with B. Now I add an Instance of B to the List of Bs A and perform a SaveOrUpdate on instance of A but the test case fails when rollback is true since ID for the instance of B is not generated.
It passes when Rollback is false, but then an entry also gets added to the database.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,DbUnitTestExecutionListener.class})
#TransactionConfiguration(transactionManager="transactionManager",defaultRollback=true)
#Transactional(propagation=Propagation.REQUIRED)
public class Test1 {
#Autowired
DummyDao dummyDao;
#Test
// #Rollback(false)
public void newTest2(){
// A temp=dummyDao.getAById(new Long(1));
A temp=dummyDao.getAs().get(0);
Hibernate.initialize(temp.getBs());
B class2=new B();
temp.getBs().add(class2);
dummyDao.saveA(temp);
assertNotNull(class2.getId());
}
}
Details of Class A
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.IndexColumn;
#Table(name="UJJWAL_DUMMY", schema="dbo")
#Entity
public class A {
#Id
#Column
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column
private String prop;
#OneToMany(fetch=FetchType.LAZY)
#Cascade({CascadeType.ALL})
#JoinColumn(name="fk_A")
#IndexColumn(name="idx")
private List<B> Bs;
// Setter and getters
}
Details of Class B
#Entity
public class B {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column
private Long id;
#Column
private String dummyColumn2;
// Setters and Getters
}
Have you tried to manually flush changes to database before checking the ids value? If id is generated in database, a flush is needed before it is set. #GeneratedValue(strategy=GenerationType.AUTO) usually defaults to column of type identity which is auto number generated in database.

Categories

Resources