I have 3 tables with a many to many relationship
A (id, name, ....) primary key id
B (id, name, ....) with primary key id
AB (id_a, id_b, date, ....) - relation table with no
primary key
Can i model the classes for hibernate so that I use IdClass and not EmbeddedId solution (so that I avoid using cascading unecessary level for calling - getId().getA())
PS tried to mix these solutions but it doesn't work:
http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/
How to map a composite key with Hibernate?
When it comes to building relationships between entities,the closest wall next to me and my head often join... (Stephan)
Here is a working example of a many to many relationship between entities A and B:
A.java
import java.util.ArrayList;
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
#Entity
public class A {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE)
#Column(name="id_a")
private Integer id;
private String name;
#OneToMany(mappedBy="a",cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<AB> abAssociations = new ArrayList<>();
// Getters and setters...
}
B.java
import java.util.ArrayList;
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
#Entity
public class B {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE)
#Column(name = "id_b")
private Integer id;
private String name;
#OneToMany(mappedBy = "b", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<AB> abAssociations = new ArrayList<>();
// Getters and setters...
}
AB.java
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#IdClass(ABid.class)
public class AB {
#Id
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private A a;
#Id
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private B b;
#Temporal(TemporalType.TIMESTAMP)
private Date date;
// Getters and setters...
}
ABid.java
import java.io.Serializable;
// The IdClass MUST implement Serializable and override #hashCode and #equals
public class ABid implements Serializable {
private static final long serialVersionUID = -2834827403836993112L;
private A a;
private B b;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((b == null) ? 0 : b.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ABid other = (ABid) obj;
if (a == null) {
if (other.a != null)
return false;
} else if (!a.equals(other.a))
return false;
if (b == null) {
if (other.b != null)
return false;
} else if (!b.equals(other.b))
return false;
return true;
}
}
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.7.Final</version>
</dependency>
Sample code
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
public static void main(String[] args) {
// * Init entity manager
EntityManagerFactory emf = Persistence.createEntityManagerFactory("playground");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// * Create two entities and persist them
// We must persist the entities first alone before we build and flush their relation
A a = new A();
a.setName("foo");
em.persist(a);
B b = new B();
b.setName("bar");
em.persist(b);
// * Build relationships between the two previous entities
AB ab = new AB();
ab.setA(a);
ab.setB(b);
ab.setDate(new Date());
a.getAbAssociations().add(ab);
b.getAbAssociations().add(ab);
// * Flush our changements in the database
em.getTransaction().commit();
em.close();
emf.close();
}
}
Here is the sql code of the tables created by Hibernate on a Postgresql database.
CREATE TABLE a
(
id_a integer NOT NULL,
name character varying(255),
CONSTRAINT a_pkey PRIMARY KEY (id_a)
)
CREATE TABLE b
(
id_b integer NOT NULL,
name character varying(255),
CONSTRAINT b_pkey PRIMARY KEY (id_b)
)
CREATE TABLE ab
(
date timestamp without time zone,
b_id_b integer NOT NULL,
a_id_a integer NOT NULL,
CONSTRAINT ab_pkey PRIMARY KEY (a_id_a, b_id_b),
CONSTRAINT fk_3exna7nsxvj1kv9i9pntmwlf1 FOREIGN KEY (a_id_a)
REFERENCES a (id_a) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_n3jrq53nr1elew4rytocopkbu FOREIGN KEY (b_id_b)
REFERENCES b (id_b) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
In response to #valik's comment.
Try this :
#Entity
public class AB {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE)
#Column(name = "id_ab")
private Integer id;
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private A a;
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private B b;
#Temporal(TemporalType.TIMESTAMP)
private Date date;
// Getters and setters...
}
Related
I'm trying to persist two entities Categorie and Question in a PostgreSQL db with one to many (categorie has many questions and a question is in one categorie).
After a lot of search and trying, adding CascadeType.PERSIST to the both entities is the only solution I found to the error but with CascadeType.PERSIST on the question side the category table we'll be full of duplicates. Is there any better solution because the categories should be unique in the table.
#Entity
#Table(name = "Category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CID")
private int categoryId;
#Column(name = "CNAME")
private String categoryName;
#OneToMany(mappedBy = "category" , cascade = CascadeType.PERSIST)
public List<Question> questions;
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Category)) {
return false;
}
Category category = (Category) o;
return categoryId == category.categoryId
&& getCategoryName().equals(category.getCategoryName())
&& questions.equals(category.questions);
}
#Override
public int hashCode() {
return Objects.hash(getCategoryName());
}
#Entity
#Table(name = "Question" )
public class Question {
#Id
#Column(name = "QID")
private int id;
#Column(name = "QText")
private String question;
#ManyToOne()
private Category category;
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Question)) {
return false;
}
Question question = (Question) o;
return getId() == question.getId();
}
#Override
public int hashCode() {
return Objects.hash(getId());
}
public persist(){
EntityManager em = getEntityManager();
em.getTransaction().begin();
for (Category c : data.getCategories()) {
em.persist(c);
}
em.getTransaction().commit();
em.close();
}
The only thing I have done to fix your problem in my local machine, was to change the type of your entities id: int to Long
Working example based on your code :
Category entity
package io.ahenteti.java;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Entity
#Table(name = "Category")
#AllArgsConstructor
#NoArgsConstructor
#NamedQueries({#NamedQuery(name = Category.FIND_ALL, query = "SELECT c FROM Category c")})
public class Category {
public static final String FIND_ALL = "Category.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CID")
private Long categoryId;
#Column(name = "CNAME")
private String categoryName;
#OneToMany(mappedBy = "category", cascade = CascadeType.PERSIST)
public List<Question> questions = new ArrayList<>();
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Category)) {
return false;
}
Category category = (Category) o;
return categoryId == category.categoryId && getCategoryName().equals(category.getCategoryName()) && questions
.equals(category.questions);
}
#Override
public int hashCode() {
return Objects.hash(getCategoryName());
}
}
Question
package io.ahenteti.java;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Entity
#Table(name = "Question")
#AllArgsConstructor
#NoArgsConstructor
#NamedQueries({#NamedQuery(name = Question.FIND_ALL, query = "SELECT q FROM Question q")})
public class Question {
public static final String FIND_ALL = "Question.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "QID")
private Long id;
#Column(name = "QText")
private String question;
#ManyToOne()
private Category category;
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Question)) {
return false;
}
Question question = (Question) o;
return getId() == question.getId();
}
#Override
public int hashCode() {
return Objects.hash(getId());
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="persistence-unit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>io.ahenteti.java.Question</class>
<class>io.ahenteti.java.Category</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:demo"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
Main
package io.ahenteti.java;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import java.util.List;
public class Main {
public static void main(String[] args) {
EntityManager em = Persistence.createEntityManagerFactory("persistence-unit").createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
em.persist(createCategory("C1"));
em.persist(createCategory("C2"));
em.persist(createCategory("C3"));
transaction.commit();
System.out.println("number of categories in database: " + getAllCategories(em).size());
System.out.println("number of questions in database: " + getAllQuestions(em).size());
}
private static List<Question> getAllQuestions(EntityManager em) {
TypedQuery<Question> getAllQuestions = em.createNamedQuery(Question.FIND_ALL, Question.class);
return getAllQuestions.getResultList();
}
private static List<Category> getAllCategories(EntityManager em) {
TypedQuery<Category> getAllCategories = em.createNamedQuery(Category.FIND_ALL, Category.class);
return getAllCategories.getResultList();
}
private static Category createCategory(String category) {
Category res = new Category();
res.setCategoryName(category);
for (int i = 0; i < 5; i++) {
res.getQuestions().add(createQuestion(res, category + " - Q" + i));
}
return res;
}
private static Question createQuestion(Category category, String question) {
Question q1 = new Question();
q1.setQuestion(question);
q1.setCategory(category);
return q1;
}
}
output
number of categories in database: 3
number of questions in database: 15
Hope it helps :)
Without much details it is hard to infer the root of your problems; so if what you want to accomplish is to persist a collection of an entity with a one to many association with another entity, then you surely do it semi brute force programmatically without chasing the problem with your annotations configuration.
First remove all CascadeType annotations from your entities.
Then write your persist method as follows:
public void persist(Collection<Category> categories) {
EntityManager em = getEntityManager();
em.getTransaction().begin();
// Persist all categories first, without persisting the questions
categories.forEach(cat -> safelyPersistCategory(em, cat));
// Associated the not yet persisted questions with the persisted categories
categories.stream().forEach(cat -> cat.getQuestions().stream().forEach(question -> question.setCategory(cat)));
// Finally persist each question
categories.stream().flatMap(cat -> cat.getQuestions().stream()).forEach(question -> em.persist(question));
em.getTransaction().commit();
em.close();
}
// Safely persists Category without trying to create a relationship to
// potentially not persisted Questions
private void safelyPersistCategory(EntityManager em, Category category) {
List<Question> questions = category.getQuestions();
category.setQuestions(null);
em.persist(category);
category.setQuestions(questions);
}
As you can see in the comments in the code you manually:
Add the Category entities to the persistence context safely (without
associating them to potentially non-managed Questions).
Then associate these managed Category entities with their Question entities.
Finally add the Question entities to the persistence context.
From there you can commit the transaction.
The reason for this sequence is that the Question entity is the owner of the relationship, so it must relate to an already persisted/managed entity (Category), otherwise it will try to link to create an association to a non-persisted/non-managed entity which would cause problems (and which I suspect was what was happening with your original IllegalStateException).
Finally, by persisting the Category entities first, you can link the Question entities to already managed entities and not create them on the fly.
Complete code on GitHub
Hope this helps.
Use Case: We have one - many bidirectional relationships and we will be receiving requests to update as a parent which contains either child being modified or not.
Technology stack
Spring boot 2.0.2
Spring data Jpa
Sample Code:
Parent Class Entity:
package com.example.demo.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Getter
#Setter
#NoArgsConstructor
#DynamicInsert
#DynamicUpdate
#Entity
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String a;
private String b;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "parent")
private Set<Child> childs = new HashSet<>();
public void addChild(Child child) {
childs.add(child);
child.setParent(this);
}
public void removeChild(Child child) {
childs.remove(child);
child.setParent(null);
}
public void setChilds(
Set<Child> childrens) {
if (this.childs == null) {
this.childs = childrens;
}
else {
this.childs.retainAll(childrens);
this.childs.addAll(childrens);
}
}
}
Child Class Entity
package com.example.demo.model;
import java.util.Objects;
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.persistence.UniqueConstraint;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Getter
#Setter
#NoArgsConstructor
#DynamicInsert
#DynamicUpdate
#Entity
#Table(name = "child", uniqueConstraints = {
#UniqueConstraint(columnNames = { "a", "b", "c", "parent_id" }) })
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String a;
private String b;
private String c;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id")
private Parent parent;
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Child)) {
return false;
}
Child that = (Child) o;
return Objects.equals(getA(), that.getA()) && Objects.equals(getB(), that.getB())
&& Objects.equals(getC(), that.getC());
}
#Override
public int hashCode() {
return Objects.hash(getA(), getB(), getC());
}
}
Repository Class:
package com.example.demo.model;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
#Repository
public interface ParentRepository extends JpaRepository<Parent, Long> {
#Query("select p from Parent p join fetch p.childs where p.a = ?1")
Parent findByA(String a);
}
Main-Class with the business case:
package com.example.demo;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.util.Assert;
import com.example.demo.model.Child;
import com.example.demo.model.Parent;
import com.example.demo.model.ParentRepository;
#SpringBootApplication
public class DemoApplication implements CommandLineRunner {
#Autowired
ParentRepository repository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
Child c1 = new Child();
c1.setA("a1");
c1.setB("b1");
c1.setC("c1");
Child c2 = new Child();
c2.setA("a2");
c2.setB("b2");
c2.setC("c2");
Parent p = new Parent();
p.addChild(c1);
p.addChild(c2);
p.setA("a");
repository.save(p);
// This works till now
// We will get the request for updating parent which might contain removal or addition of the child
Parent retrievedParent = repository.findByA("a");
retrievedParent.setB("b");
Child c4 = new Child();
c4.setA("a2");
c4.setB("b2");
c4.setC("c2");
Child c3 = new Child();
c3.setA("a3");
c3.setB("b3");
c3.setC("c3");
//If we know that c1 is removed and c3 is added we can use synchronize methods written in Parent
//As we don't know which are removed and which are added also as we won't get the id from request passing them
// directly to set to let hibernate handle it as equals and Hashcode is already written.
Set<Child> childrens = new HashSet<>();
childrens.add(c3);
childrens.add(c4);
retrievedParent.setChilds(childrens);
Parent persistedParent = repository.save(retrievedParent);
for (Child child : persistedParent.getChilds()) {
Assert.notNull(child.getParent(), "Parent must not be null");
//For child 3 it is failing
}
}
}
With above code, it is unable to set the parent id for child entity 4, if we print SQL logs we can observe that child with id 1 is deleted and child with id 3 is inserted which is expected.
As a workaround I am iterating all child entries and if the parent is not set then setting manually. I don't want this extra update statement.
Other approaches tried, removing all child entries using synchronized removeChild method and then add remaining one by one using synchronized addChild method . This is causing unique constraint failure exception.
What is required?
Setting the parent instead of workaround in the insert statement when it is executed.
The problem comes from this part:
Set<Child> childrens = new HashSet<>();
childrens.add(c3);
childrens.add(c4);
retrievedParent.setChilds(childrens);
You never need to rewrite a managed collection.
Now, based on your design:
If we know that c1 is removed and c3 is added we can use synchronize
methods written in Parent.
As we don't know which are removed and
which are added also as we won't get the id from request passing them
directly to set to let hibernate handle it as equals and Hashcode
is already written.
If the client sends you a collection of entries, you need to do the matching yourself, meaning that you need to:
add new elements
remove elements that are no longer needed
update the existing ones
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;
}