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.
Related
I have a postgres db with a column that has polygon type. When I try to save something in this table i get the following error:
org.postgresql.util.PSQLException: ERROR: column "polygon" is of type polygon but expression is of type bytea
Hint: You will need to rewrite or cast the expression.
How do I cast this?
This is the class that represents the table
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.annotations.Type;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.validation.annotation.Validated;
import javax.persistence.*;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
#Validated
#Entity
#Table(name="boundary", schema = "public")
#JsonIgnoreProperties(value = "id")
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2019-03-09T16:35:39.240Z[GMT]")
public class Boundary {
#Id
#Column(name = "boundary_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
#Column(name = "polygon")
private Polygon polygon;
#OneToOne
#JoinColumn(name="field_id")
private FieldResource field;
I'm having troubles in creating a custom query within spring, because my Entity contains an "_" character in it's parameter's name: "game_date".
My table has a column named "game_date" as well.
I have created following method:
List<Games> findByGame_dateAndOpponent(#Param("game_date") Date game_date, #Param("opponent") String opponent);
but when I start my app, it's crashing with exception of kind: "org.springframework.data.mapping.PropertyReferenceException: No property gamedate found for type Games!". After changing a parameter name to the "gameDate" both in Entity and Query method, it stopped complaining, and is actually returning expected entries. But at the same time, it doesn't return values from the column "game_date", in the search queries, which is a simple regular column of a Date type. I have no idea what's going on with all this thing.
DB I'm using is MySql.
Here comes the code itself:
Entity:
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name = "games")
public class Games {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_game")
private int id;
#Column(name = "game_date", columnDefinition = "DATE")
#Temporal(TemporalType.DATE)
private Date gameDate;
public Date getGame_date() {
return gameDate;
}
public void setGame_date(Date _game_date) {
this.gameDate = _game_date;
}
}
And a repository:
import java.sql.Date;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource
public interface GamesRepository extends CrudRepository< Games , Integer > {
List< Games > findById( #Param( "id" ) int id );
List< Games > findAll( );
List<Games> findByGameDateAndOpponent(#Param("game_date") Date game_date, #Param("opponent") String opponent);
}
The underscore is a reserved keyword in Spring Data JPA. It should be enough to remove it from your property and from its getters and setters and Hibernate will do the rest:
#Entity
#Table(name = "games")
public class Games {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_game")
private int id;
//Getter and setters for id
#Column(name = "game_date")
private Date gameDate;
public Date getGameDate() {
return gameDate;
}
public void setGameDate(Date gameDate) {
this.gameDate = gameDate;
}
}
Also, in general, try to use java naming convention for variable and field names, which is mixed case with lowercase first.
See also:
Spring Data JPA repository methods don't recognize property names with underscores
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;
}
}
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;
}
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.