Update Associated entity on updatign foreign key - Hibernate - java

I have a mysql table which maintains data of drivers and maintains the city of the driver by using the foreign key mapping.
public class Drivers {
private Integer currentCityId;
private Integer id;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "current_city_id")
public Integer getCurrentCityId() {
return currentCityId;
}
public void setCurrentCityId(Integer currentCityId) {
this.currentCityId = currentCityId;
}
#ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
#JoinColumn(name = "current_city_id", insertable = false, updatable = false, nullable = true, unique = false)
public Cities getCities() {
return cities;
}
public void setCities(Cities cities) {
this.cities = cities;
}
}
#Entity
#Table(name = "cities", catalog = "mytable_production", uniqueConstraints = #UniqueConstraint(columnNames = "name"))
public class Cities implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String aliasName1;
private String aliasName2;
private int stateId;
}
Now, I am updating the city of the driver by updating the foreignKey value in the table using
#Transactional
public void updateCityBizLogic(int driverId,int newCityId) {
//Some biz logic
Drivers d = driversDao.updateCity(driverId,newCityId);
log.info("Updated driverCity to {}",d.getCities.getName());
}
public class DriversDao {
#Transactional
public Drivers updateCity(int DriverId, int newCityId) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Drivers.class);
criteria.add(Restrictions.eq("id", Integer.parseInt(id)));
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Drivers d = criteria.list().get(0);
d.setCurrentCityId(newCityId);
session.update(d);
return d;
}
}
But in the log line, it is printing the old city name. I want the session to update the associated entities when I update any of the foreign key ( like update the joined cities object, when I update the cityId)
Can someone point out what I am missing here and achieve it?

Related

Incorrect count on manyToMany hibernate mapping

I've a bidirectional relationship between two entities: Item (15 records) and maintenanceContract (22 records)
Mapping table item_maintenanceContract linking these two entities contains 25 records
I would like to count the records in the maintenanceContract table and I run the following query:
"SELECT count(*) FROM MaintenanceContract mc LEFT JOIN mc.items as i "
Unfortunately I visualize 25 instead of the desidered 22.
I cannot simply count on MaintenanceContract because join with Item is required when i perform same searches based on item attributes.
I tried alternative combinations: LEFT JOIN , left outer JOIN, right JOIN... no changes in the result
What I'm missing?
My item definition:
#Entity
#Table(name = "item"})
#Inheritance(strategy = InheritanceType.JOINED)
public class Item extends BaseEntity implements Serializable {
private Long id;
private Set<MaintenanceContract> maintenanceContracts = new HashSet<MaintenanceContract>(0);
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "item_maintenancecontract", joinColumns = {
#JoinColumn(name = "item_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "maintenancecontract_id",
nullable = false, updatable = false)})
public Set<MaintenanceContract> getMaintenanceContracts() {
return maintenanceContracts;
}
public void setMaintenanceContracts(Set<MaintenanceContract> maintenanceContracts) {
this.maintenanceContracts = maintenanceContracts;
}
}
and my MaintenanceContract
#Entity
public class MaintenanceContract implements Serializable {
private Long id;
private Set<Item> items = new HashSet<Item>(0);
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "maintenanceContracts")
public Set<Item> getItems() {
return this.items;
}
public void setItems(Set<Item> items) {
this.items = items;
}
}

Why PostgreSQL is forcing me to use just one primary key on a cross-table?

I'm trying to save an object with hibernate using one to many relationship and PostgreSQL is forcing me to have just one primary key on a cross-table. The thing I want to do is to make a cross table have 2 primary keys together. So I can avoid the duplicate foreign key exception.
I have been searching for while on how to overcome this but i can't get it right. Is this something that PostgreSQL do by default? or do i have to use MySQL?
Any tips on why this is happening?
*Note: Also if I insert on the cross-table one set of "Tratamiento" different every time, it works fine. The problem comes when I'm trying to save a Tratamiento that was stored before but with a different Cita, in theory that's good because of the 2 columns being primary key, it doesn't mean a problem. But since PostgreSQL is forcing the cross-table to have just a one primary key, that's when the problem comes.
Here is the class I'm trying to save:
#Entity
#Table(name = "CITA", schema = "COLINASCO")
public class Cita implements Serializable{
private long id;
private Date fecha;
private Time hora;
private Paciente paciente;
private Empleado empleado;
private Set<Tratamiento> listaTratamientos;
public Cita() {
fecha = null;
hora = null;
paciente = null;
empleado = null;
listaTratamientos = null;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CITA_ID", nullable = false, unique = true)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "FECHA", nullable = false)
public Date getFecha() {
return fecha;
}
public void setFecha(Date fecha) {
this.fecha = fecha;
}
#Column(name = "HORA", nullable = false)
public Time getHora() {
return hora;
}
public void setHora(Time hora) {
this.hora = hora;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "PACIENTE_ID")
public Paciente getPaciente() {
return paciente;
}
public void setPaciente(Paciente paciente) {
this.paciente = paciente;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "EMPLEADO_ID")
public Empleado getEmpleado() {
return empleado;
}
public void setEmpleado(Empleado empleado) {
this.empleado = empleado;
}
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "CITA_TRATAMIENTO", joinColumns = {#JoinColumn(name = "CITA_ID")},
inverseJoinColumns = {#JoinColumn(name = "TRATAMIENTO_ID")},
uniqueConstraints = {#UniqueConstraint(columnNames = {"CITA_ID","TRATAMIENTO_ID"}, name = "CITA_TRATAMIENTO_PK")},
schema = "COLINASCO")
public Set<Tratamiento> getListaTratamientos() {
return listaTratamientos;
}
public void setListaTratamientos(Set<Tratamiento> listaTratamientos) {
this.listaTratamientos = listaTratamientos;
}
}
Note that the object class on the Set doesn't have a "Cita" class. That's why I didn't put it in here.
Thanks in advance if someone could help me on this.
From the PostgreSQL docs:
A table can have at most one primary key.
What you want is a composite key on two columns. The DDL will look something like:
CREATE TABLE cross (
id integer PRIMARY KEY,
t1_id integer REFERENCES t1,
t2_id integer REFERENCES t2,
UNIQUE (t1_id, t2_id)
);
You'll have to see your ORM documents to see how to do a constraint on a composite key.

hibernate h2 not generating relations

I'm trying to generate Hibernate mapping to my H2 database.
I have 2 tables for test, called users and users_groups.
They look like:
users table:
user_id integer PK
login varchar
password varchar
user_group_id integer FK
users_groups
user_group_id integer PK
name varchar
And the problem is that hibernate generate entities like that:
#Entity
public class Users {
private int userId;
private int userGroupId;
#Id
#Column(name = "USER_ID", nullable = false)
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
#Basic
#Column(name = "USER_GROUP_ID", nullable = false)
public int getUserGroupId() {
return userGroupId;
}
public void setUserGroupId(int userGroupId) {
this.userGroupId = userGroupId;
}
#Entity
#Table(name = "USERS_GROUPS", schema = "PUBLIC", catalog = "DATABASE")
public class UsersGroups {
private int userGroupId;
#Id
#Column(name = "USER_GROUP_ID", nullable = false)
public int getUserGroupId() {
return userGroupId;
}
public void setUserGroupId(int userGroupId) {
this.userGroupId = userGroupId;
}
So no relation annotations are generated, like #OneToMany or #ManyToMany etc. What am I doing wrong? Thanks for your help.
p.s. I want it to generate mapping like
Users class with field of UserGroup type
If the classes were auto generated like this check your relation in the database between the two tables and make sure you choose the right schema your mapping is completely wrong the for example :-
1-the auto generated classes your mapping are missing some columns, class User doesn't contain password and login columns and class UsersGroups doesn't contain name column.
2- class User doesn't have #table annotation
They should look something like this :-
Class UserGroups
#Entity
#Table(name = "USERS_GROUPS", schema = "PUBLIC", catalog = "DATABASE")
public class UsersGroups implements java.io.Serializable {
private int userGroupId;
private String name;
private Set<Users> users = new HashSet<Users>(0);
public UsersGroups() {
}
#Id
#GeneratedValue(strategy = IDENTITY) //this to make the id auto increment
#Column(name = "user_group_id", nullable = false)
public int getUserGroupId() {
return userGroupId;
}
public void setUserGroupId(int userGroupId) {
this.userGroupId = userGroupId;
}
// if name column is not unique / nullable remove values from annotation
#Column(name = "name", unique = true, nullable = false, length = 10)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name= name;
}
#OneToMany(fetch = FetchType.EAGER, mappedBy = "users_groups")
public Set<Users> getUsers() {
return this.users;
}
public void setUsers(Set<Users> users) {
this.users= users;
}
}
Class Users
#Entity
#Table(name = "users", schema ="PUBLIC" , catalog ="DATABASE")
public class Users implements java.io.Serializable {
private Integer userId;
private UsersGroups usersGroups;
private String password;
private String login;
public Users() {
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "user_id", unique = true, nullable = false)
public Integer getUserId() {
return this.userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_group_id", nullable = false)
public UsersGroups getUsersGroups() {
return this.usersGroups;
}
public void setUsersGroups(UsersGroups usersGroups) {
this.usersGroups = usersGroups;
}
#Column(name = "password",length = 10)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name = "login",length = 10)
public String getLogin() {
return this.login;
}
public void setLogin(String login) {
this.login = login;
}
}
Check this full example for one to many mapping

How can i fetch foreign key id directly instead of entire entity in case of lazy loading using Hibernate?

My Entity is as follows:-
#Entity
#Table(name = "state")
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
public class State implements java.io.Serializable {
private Integer id;
private Country Country;
private String name;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "country", nullable = false)
#JsonManagedReference(value="country-state")
public Country getCountry() {
return this.country;
}
public void setCountry(Country country) {
this.country = country;
}
}
In this entity instead of Entire country just i want to fetch foreign key id value...
For accessing foreign key (id) directly, is there any option in Hibernate?
You can also add (depending on you id column name):
#Column(name = "COUNTRY_ID")
private Long countryId;
A workaround is to add a dummy property to your entity and set it as insertable = false, updatable = false.
String countryKey;
#Column(name = "country", insertable = false, updatable = false)
public String getCountryKey() {
return this.countryKey;
}

Hibernate mapping in Java: org.hibernate.MappingException: Repeated column in mapping for entity

I try to gather statistics of visitors for two services. It consists of daily visitors statistics and overall record. Each service can be accessed by different names. For example, user, admin, support etc. Each will have its own record as own statistics.
Here is my DB structure:
service_one: id, name
service_two: id, name
daily_stats: id, date, service_one_id, service_one_visitors,
service_two_id, service_two_visitors, overall_visitors
record_stats: id, service_one_id, service_one_record,
service_one_record_date, service_two_id, service_two_record,
service_two_record_date
Here are the relations between tables:
service_one --- (one to many) ---> daily_stats(service_one_id)
service_one --- (one to many) ---> record_stats(service_one_id)
service_two --- (one to many) ---> daily_stats(service_two_id)
service_two --- (one to many) ---> record_stats(service_two_id)
Mapping for service_one (the same is for service_two). Also setters were omitted in order to shorten the example:
#Entity
#Table(name = "service_one")
public class ServiceOne implements Serializable {
private int id;
private String name;
private Set<RecordStats> recordStats = new HashSet<RecordStats>(0);
private Set<DailyStats> dailyStats = new HashSet<DailyStats>(0);
public ServiceOne() {}
public ServiceOne(int id, String name) {
this.id = id;
this.name = name;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", nullable = false, unique = true)
public int getId() {
return id;
}
#Column(name = "name")
public String getName() {
return name;
}
#OneToMany(fetch = LAZY, mappedBy = "service_one_id")
public Set<RecordStats> getRecordStats() {
return recordStats;
}
#OneToMany(fetch = LAZY, mappedBy = "service_one_id")
public Set<DailyStats> getDailyStats() {
return dailyStats;
}
}
daily_stats mapping:
#Entity
#Table(name = "daily_stats", uniqueConstraints = {
#UniqueConstraint(columnNames = "date")
})
public class DailyStats implements Serializable{
private int id;
private Date date;
private ServiceOne service_one_id;
private int service_one_visitors;
private ServiceTwo service_two_id;
private int service_two_visitors;
private int overall_visitors;
public DailyStats() {}
public DailyStats(DailyStats rec) {
this.id = rec.getId();
//...
}
#Id
#GeneratedValue
#Column(name = "id", nullable = false)
public int getId() {
return id;
}
#Temporal(DATE)
#Column(name = "date")
public Date getDate() {
return date;
}
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "id", nullable = false)
public ServiceOne getService_one_id() {
return service_one_id;
}
#Column(name = "service_one_visitors")
public int getService_one_visitors() {
return service_one_visitors;
}
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "id", nullable = false)
public ServiceTwo getService_two_id() {
return service_two_id;
}
#Column(name = "service_two_visitors")
public int getService_two_visitors() {
return service_two_visitors;
}
#Column(name = "overall_visitors")
public int getOverall_visitors() {
return overall_visitors;
}
}
record_stats mapping:
#Entity
#Table(name = "record_stats", uniqueConstraints = {
#UniqueConstraint(columnNames = "service_one_record_date"),
#UniqueConstraint(columnNames = "service_two_record_date")
})
public class RecordStats implements Serializable {
private int id;
private ServiceOne service_one_id;
private int service_one_record;
private Date service_one_rec_date;
private ServiceTwo service_two_id;
private int service_two_record;
private Date service_two_rec_date;
public RecordStats() {}
public RecordStats(RecordStats rec) {
this.id = rec.getId();
//...
}
#Id
#GeneratedValue
#Column(name = "id", nullable = false)
public int getId() {
return id;
}
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "id", nullable = false)
public ServiceOne getService_one_id() {
return service_one_id;
}
#Column(name = "service_one_record")
public int getService_one_record() {
return service_one_record;
}
#Column(name = "service_one_record_date")
#Temporal(DATE)
public Date getService_one_rec_date() {
return service_one_rec_date;
}
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "id", nullable = false)
public ServiceTwo getService_two_id() {
return service_two_id;
}
#Column(name = "service_two_record")
public int getService_two_record() {
return service_two_record;
}
#Column(name = "service_two_record_date")
#Temporal(DATE)
public Date getService_two_rec_date() {
return service_two_rec_date;
}
}
Trying to create new entry throws exception:
public static void main(String[] args) {
ServiceOne serviceOne = new ServiceOne();
serviceOne.setName("test");
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(serviceOne);
session.getTransaction().commit();
//get records
session = sessionFactory.openSession();
session.beginTransaction();
List result = session.createQuery("from service_one").list();
for (ServiceOne o : (List<ServiceOne>)result) {
System.out.println(o.getName());
}
session.getTransaction().commit();
session.close();
}
org.hibernate.MappingException: Repeated column in mapping for entity:
VisitorsCounter.model.entity.DailyStats column: id (should be
mapped with insert="false" update="false")
What is wrong with my mapping?
It seems to me that
#JoinColumn(name = "id", nullable = false)
public ServiceOne getService_one_id() {
return service_one_id;
}
in DailyStats is wrong; you should have name = "service_one_id".
You have the same problem in getService_two_id() and in methods of same names in RecordStats.
May I also ask why don't you name the references in the classes fields serviceOne and serviceTwo instead of service_one_id and service_two_id.

Categories

Resources