Using JPA and Hibernate
I have an entity class
#Entity
#Table(name = "ROLES")
public class Role implements Serializable
{
#Column
private List<String> tubes;
// another fields .setters, getters
}
Every String in List tubes - is one row from another table (TUBES).
Table ROLES has an OneToMany relationship with TUBES.
A can make another Entity Tubes and map table TUBES on Entity Tubes. But how I can make this without another entity?
Edit:
I made
#ElementCollection
#CollectionTable(name = "TUBES", joinColumns = #JoinColumn(name = "role_id"))
#Column(name = "tube")
private ArrayList<String> tubes;
Deploy on JBoss. And in runtime I get SQLGrammarException
Query created by JPA is:
/* SELECT r FROM Role r WHERE r.name = ? */ select role0_.AA_ID as AA1_0_, role0_.ROLNAME as ROLNAME0_, role0_.role as PID4_0_ from PIDDB_PID_ROLE role0_ where role0_.ROLNAME=?
17:17:14,661 ERROR [JDBCExceptionReporter] ORA-00904: "ROLE0_"."tube": invalid identifier
You can use #ElementCollection mapping I think this is what are you looking for.
#ElementCollection(fetch=FetchType.LAZY)
#CollectionTable(name="TUBES", joinColumns=#JoinColumn(name="role_id"))
#Column(name="tube")
private List<String> tubes;
Update:
dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
**Update2:**
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
Related
Situation:
(using Payara Server)
I have multiple Groups, and each Group has their own specific set of GroupMeetings.
These GroupMeetings are tracked over multiple years.
Each Group contains 100-10000 GroupMeetings.
But usually only the current year's GroupMeetings are queried and used.
Problem:
How can I load all Groups, but only load each Group's GroupMeeting List for a specific interval, for example only the GroupMeetings of 2019? Or, if need be, specific years or ranges, i.e. 2017-2021 etc?
If I simply run a "SELECT *", then with the FetchType.LAZYI will get empty an emtpy List<GroupMeeting>, but as soon as I access it somewhere in the code, all the items will be loaded.
Question:
Whats the best strategy, i.e. somewhat efficient but not overly convoluted?
Is there an easy SQL/JPQL query that I can run with the classes below?
Is there some structural change - especially in the annotations - needed?
Should I consider Criteria API?
Do I have to use two List<GroupMeeting>s, one with the commonly used meetings, the other with the 'old' meetings?
Example:
Here are the two classes:
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
#Entity
public class Group {
#Id //
#GeneratedValue() //
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) #JoinTable(name = "group_meetings") //
private final List<GroupMeeting> meetings = new ArrayList<>();
}
and
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class GroupMeeting {
#Id //
#GeneratedValue() //
private long id;
private String title;
private Date start;
private Date end;
}
You can use Hibernate filters to achieve that, for instance:
#Entity
#FilterDef(name="groupMeetingFilter",
parameters={#ParamDef( name="fromDate", type="date"), #ParamDef(name="toDate", type="date")} )
public class Group {
#Id //
#GeneratedValue() //
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) #JoinTable(name = "group_meetings")
#Filter(
name = "groupMeetingFilter",
condition="start <= :fromDate and end >= :toDate"
)
private final List<GroupMeeting> meetings = new ArrayList<>();
}
And you need to enable your filter somewhere in your application, just like this:
Session session = HibernateUtil.getSessionFactory().openSession();
Filter filter = session.enableFilter("groupMeetingFilter");
//Define here the dates that you want
filter.setParameter("fromDate", new Date());
filter.setParameter("toDate", new Date());
You could go further with your research and make the filter global available, if you're using Spring for instance, is easier.
I need to create entity based on information from database. Based on database I created string like this :
` package az.com.ds.entity.crudEntity;
import javax.persistence.Table;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Column;
#Table(name = "CMN_SP", schema = "CMN")
#Entity
public class CmnSpEnt {
#Id
private Integer id;
#Column(name = "NAME")
private String name;
} `
Then I created java file based on this string and compiled it at runtime. Everything works perfectly to this step. But when I want to get data based on entity it throws exception as
org.hibernate.hql.internal.ast.QuerySyntaxException: CmnSpEnt is not mapped [Select x from CmnSpEnt x ].
Now I need to map entity for hibernate in order to get data from database. Is there a way to accomplish this?
I am trying to run sql scripts on startup of the webapp using hibernate.hbm2ddl.import_files, but this doesn't seem to be working. I am using the following in my persistence.properties:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost/rays_rentals?createDatabaseIfNotExist=true
dataSource.username=root
dataSource.password=
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create
hibernate.hbm2ddl.import_files=bikes.sql
My bikes.sql file is saved in the same place as my properties file.
Here is my sql file:
INSERT INTO `bikes` (`id`, `brand`, `model`) VALUES (1, 'Giant', 'Propel Advanced 0');
Here is my Bike model:
package com.BrightFuture.RaysRentalSystem.bikes;
import java.util.ArrayList;
import java.util.List;
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 javax.persistence.Table;
import org.hibernate.annotations.Proxy;
#Entity
#Proxy(lazy = false)
#Table(name = "bikes")
public class Bike {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy="bike", cascade=CascadeType.ALL)
private List<BikeRecord> bikeRecords = new ArrayList<BikeRecord>();
#Column(name="brand", nullable=false)
private String brand;
#Column(name="model", nullable=false)
private String model;
}
Thanks.
I solved this issue. everything in my question is right.. i was just missing the configuration for it in my JpaConfig
Please modify your properties file with below attribute:
hibernate.hbm2ddl.auto=update
I am having three class. Person,vehicle and a association class to link the person and vehicle
Person
package entity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="PERSON")
public class Person {
#EmbeddedId
private PKperson pkPerson;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade=CascadeType.ALL,mappedBy="person")
private Set<PersonVehAssnVO> personVehAssnVOSet=new HashSet<PersonVehAssnVO>();
//getters & setters
}
PKperson
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;
#Embeddable
public class PKperson implements Serializable {
#Column(name="NAME", nullable=false)
private String name;
#Column(name="DOB_DT", nullable=false)
private Date dobDt;
}
Vehicle
package entity;
import java.util.Date;
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.OneToMany;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="VEHICLE")
public class Vehicle {
#Id
#Column(name="VEHICLE_ID",unique=true, nullable=false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_name")
#SequenceGenerator(allocationSize = 1, name = "seq_name", sequenceName = "SEQ_VEHICLE_ID")
private Long vehicleId;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade=CascadeType.ALL,mappedBy="vehicle")
private Set<PersonVehAssnVO> personVehAssnVOSet=new HashSet<PersonVehAssnVO>();
private String vehicleName;
//getters & setters
}
Person Vehicle Association
package entity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="PERSON_VEHICLE_ASSOC")
public class PersonVehAssnVO {
#EmbeddedId
private PKperson pkPerson;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "pkPerson.name",referencedColumnName ="NAME"),
#JoinColumn(name = "pkPerson.dobDt",referencedColumnName ="DOB_DT")})
private Person person;
#ManyToOne
#JoinColumn(name = "VEHICLE_ID", referencedColumnName = "VEHICLE_ID")
private Vehicle vehicle;
//getters & setters
}
//**Save Method**
PKperson pkPerson = new PKperson();
SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = dtFormat.parse("1984-12-14");
pkPerson.setName("Magesh");
pkPerson.setDobDt(date1);
Person person = new Person();
person.setPKperson(pkPerson);
Vehicle vehicle = new Vehicle();
vehicle.setName("Honda350");
PersonVehAssnVO perVehAssnVO = new PersonVehAssnVO();
PersonVehAssnVO.setPKperson(pkPerson);
PersonVehAssnVO.setVehicle(vehicle);
Set<PersonVehAssnVO> assocSet = new HashSet<PersonVehAssnVO>();
assocSet.add(PersonVehAssnVO);
person.setpersonVehAssnVOSet(assocSet);
vehicle.setpersonVehAssnVOSet(assocSet);
Session session = getHibernateTemplate().getSessionFactory().openSession();
transaction = session.beginTransaction();
transaction.begin();
session.save(person);
transaction.commit();
//=============================================================
While Executing the above save logic I am getting error ": [entity.PersonVehAssnVO#component[name,dobDt]{dobDt=magesh, dobDt=1984-12-14 00:00:00}]"
Show Sql Gives "select personVehAssnVO_.NAME, personVehAssnVO_.DOB_DT, personVehAssnVO_.VEHICLE_ID as vehicle_34 from PERSON_VEHICLE_ASSOC where personVehAssnVO_.NAME=? and personVehAssnVO_.DOB_DT=?"
I want to save Person,Vehicle and association in a single save means CASCADE ALL When I save Person.
Any help appreciated
Mark the date in PKPerson with the #Temporal annotation:
#Temporal(TemporalType.TIME)
#Column(name="DOB_DT", nullable=false, length = 8)
private Date dobDt;
According to the Java Doc
This annotation must be specified for persistent fields or properties
of type java.util.Date and java.util.Calendar. It may only be
specified for fields or properties of these types.
The Temporal annotation may be used in conjunction with the Basic
annotation, the Id annotation, or the ElementCollection annotation
(when the element collection value is of such a temporal type.
And according to this SO question:
In plain Java APIs, the temporal precision of time is not defined.
When dealing with temporal data you might want to describe the
expected precision in database. Temporal data can have DATE, TIME, or
TIMESTAMP precision (ie the actual date, only the time, or both). Use
the #Temporal annotation to fine tune that.
I hope this solves your problem. You can interchange the TemporalType with others that match your field type in the database. The column length also can be changed accordingly.
Edit
I think you also need to remove the mappedBy="person" and mappedBy="vehicle" from the annotation of the PersonVehAssnVO sets in the Person and Vehicle classes and replace them with full column properties so that these classes can be the owners of the relationship. Otherwise when you save a person, it will ignore updating any properties marked with the mappedby annotation because this means the Person is not the owner of that relationship.
I have a OneToMany relationship, I can insert records but can not delete them, when I try to delete it runs into " a foreign key constraint fails" error. I have used cascade delete orphan as following but does not work yet.
Parent class has following getter for its member
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
#Entity
#DynamicUpdate
public class User extends Employee{
private string userli;
privae List<Message> messagelist();
.....
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
public List<Message> getMessagelist() {
return messagelist;
}
Member class has following getter for its parent
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
......
#ManyToOne
public User getReciever() {
return reciever;
}
I used following annotation as well but did not work
#Cascade(org.hibernate.annotations.CascadeType.DELETE)
My hibernate dependency is as following
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.1.Final</version>
<type>jar</type>
</dependency>
My code to remove the message
Message message = (Message) session.get(Message.class, id);
session.delete(message);
tx.commit();
Try to change the cascade = cascadeType.ALL
and check
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
public List<Message> getMessagelist() {
return messagelist;
It might work but not sure
There are a few ways to work with an OneToMany relationship. One of the most common way would be like:
#OneToMany(mappedBy="receiver", CascadeType.REMOVE)
public List<Message> getMessagelist() {
return messagelist;
}
....
#ManyToOne
public User getReciever() {
return reciever;
}
Note that fetch = FetchType.LAZY is the default you do not really need to specify it.
Additionally, you may need to recreate you tables because the db constraint has been created already. Do not trust 100% on hbm2ddl.auto=update in this case. I would suggest dropping the relevant tables (Message, Reciver, and Receiver_Message or Message_Receiver). Next, you can use hbm2ddl.auto=update.
I hope it helps.
Cheers
Try adding following annotations. It worked for me.
#OneToMany(mappedBy="receiver", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
public Set<Message> getMessagelist() {
return messagelist;
}
I am using entity manager remove method and it works for me. I am using Set instead of List, which is a efficient way, in my opinion.
Delete orphan annotation is just for telling hibernate that if "I remove entity from MessageList and try to merge User then you can safely delete Message"
#Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)