Hibernate extra queries, issue with #GeneratedValue - java

Problem with Hibernate and associations (mapping) for existing child values and the #GeneratedValue strategies. Additional queries are needed?
I am learning Hibernate, and practicing with my own example using one-to-many, many-to-one and many-to-many associations.
Simplifying for the sake of the query:
I have Java classes User, Country and Languages. One User can only live in one Country (so relation is many-to-one) and can speak several Languages (so relation is many-to-many)
I have database tables 'users', 'countries', 'languages' and 'users_languages'. The 'country_id' is stored in the 'users' table (because there is only one per user), and the several 'language_id' and 'user_id' are stored in the 'users_languages' table.
I have prefilled the tables 'countries' and 'languages', as these are fixed values, so that I do not want to add/remove any of these values from these tables. They will be associated to the different users.
The schema of the tables (I removed columns for brevity):
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`country_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username_UNIQUE` (`username`),
CONSTRAINT `u_country_fk` FOREIGN KEY (`country_id`) REFERENCES `countries` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
)
CREATE TABLE `countries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`)
)
CREATE TABLE `languages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`language` varchar(15) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `language_UNIQUE` (`language`)
)
CREATE TABLE `users_languages` (
`user_id` int(11) NOT NULL,
`language_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`language_id`),
CONSTRAINT `ul_language_fk` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `ul_user_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
)
As commented, I already inserted the needed rows in tables 'countries' and 'languages' so that those will be the only available for the users.
The corresponding Java entities:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#NaturalId
#Column(name = "username", nullable = false, unique = true)
private String username;
#ManyToOne
#JoinColumn(name="country_id",
foreignKey = #ForeignKey(name = "u_country_fk"))
private Country country;
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#LazyCollection(LazyCollectionOption.FALSE)
#JoinTable(
name = "users_languages",
joinColumns = #JoinColumn(name = "user_id", nullable = false),
inverseJoinColumns = #JoinColumn(name = "language_id", nullable = false)
)
private List<Language> languages;
public User() {
this.languages = new ArrayList<>();
}
public User(String username, Country country) {
this.username = username;
this.country = country;
this.languages = new ArrayList<>();
}
public void addLanguage(Language language) {
this.languages.add(language);
language.getUsers().add(this);
}
public void removeLanguage(Language language) {
this.languages.remove(language);
language.getUsers().remove(this);
}
public void removeAllLanguages() {
this.languages.clear();
}
// getters and setters omitted
}
#Entity
#Table(name = "countries")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#NaturalId
#Column(name = "name", nullable = false, unique = true)
private String name;
// #OneToMany(cascade = CascadeType.ALL)
// #JoinColumn(name="id")
// private Set<User> users;
public Country() {
// users = new HashSet<>();
}
public Country(String name) {
this.name = name;
// users = new HashSet<>();
}
// getters and setters omitted
}
#Entity
#Table(name = "languages")
public class Language {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#NaturalId
#Column(name = "language", nullable = false, unique = true)
private String language;
#ManyToMany(mappedBy = "languages")
Set<User> users;
public Language() {
users = new HashSet<>();
}
public Language(String language) {
this.language = language;
users = new HashSet<>();
}
// getters and setters omitted
}
When creating a new user, I have had issues with the #GeneratedValue, because in the batch I have to store several languages. Finally the one which worked for me is GenerationType.IDENTITY, but I read about the extra query required by Hibernate to know the next id to use. Furthermore, because the batch if I create a new object Language (which already exists in the database), there is an issue (I expected that Hibernate could manage this automatically). The same for new object Country. Therefore, instead of creating new objects, as the corresponding rows already exist in the database, I am getting them from the database, to associate them to the user being created. But I think that Hibernate will do again the same queries (check the existence in the database of the objects Language and Country being associated to the user), so that probably I am duplicating the number of required queries, reducing the performance. See code snippet below:
public int addUser(SessionFactory factory, String username, String countryName, String[] languages) {
User user = null;
try (Session session = factory.openSession()) {
Transaction transaction = session.beginTransaction();
Country country = (Country) session
.createQuery("FROM Country WHERE name = :country_name")
.setParameter("country_name", countryName).getSingleResult();
user = new User(username, password, name, email, gender, country);
for (String language : languages) {
Language lang = (Language) session
.createQuery("FROM Language WHERE language = :language")
.setParameter("language", language).getSingleResult();
user.addLanguage(lang);
}
session.persist(user);
transaction.commit();
}
return user==null ? -1 : user.getId();
}
Can someone please help me with the below points:
Am I using the correct strategy for generating the ids?
Am I using the correct cascade methodology (both in database and Hibernate)?
Is there a better way for the above procedure for addigin a user, reducing the total number of queries to the database / increasing the performance?
Should I make the Country association biderectional as well? Recommendations about uniderectional/bidirectional for both Country and Language classes.
Any other suggestion / improvement I should apply with Hibernate?
Many thanks in advance,
Javier

Related

Spring-Hibernate Many-to-Many : Save an entity, or create a relationship if it exists in the database

I am new to Spring and Hibernate and ran into a problem that I cannot solve for a few more days.
In my project, I use a Many-To-Many relationship between the Server and User entities. A user can exist on multiple servers.
My idea is:
Servers <-> Server_Users <-> Users
Code for creating tables:
CREATE TABLE public.servers (
id bigint NOT NULL,
s_snowflake bigint NOT NULL,
name character varying(64) NOT NULL
);
CREATE TABLE public.users (
id bigint NOT NULL,
u_snowflake bigint NOT NULL,
name character varying(64) NOT NULL
);
CREATE TABLE public.server_users (
id bigint NOT NULL,
server_id bigint NOT NULL,
user_id bigint NOT NULL
);
This is how my classes look like:
#Entity
#Table(name = "servers")
public class Server {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "s_snowflake", unique = true)
private long snowflake;
private String name;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "server_users",
joinColumns = #JoinColumn(name = "server_id"),
inverseJoinColumns = #JoinColumn(name = "user_id")
)
private Set<User> users = new HashSet<>();
}
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "u_snowflake", unique = true)
private long snowflake;
private String name;
#ManyToMany(mappedBy = "users", targetEntity = Server.class, fetch = FetchType.EAGER)
private Set<Server> servers = new HashSet<>();
}
This works well when I initialize the data. I create a Server object and populate it with users and everything is saved correctly.
But I get problems when I try to save a server that contains users that are already in the Users table (users shouldn't get deleted if I cascade delete the server from the database).
Is there any way to configure Hibernate so that it adds new Users if necessary, but if the User exists, "create relationship" it to new servers using the Server_Users table?
I tried putting Cascade.SAVE_UPDATE and another ways, but it gave no results.
Addiction:
This is DAO class methods that I use to save and update:
public abstract class AbstractDAOImpl<T> implements AbstractDAO<T> {
public void save(T entity) {
Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
Transaction trx = session.beginTransaction();
session.save(entity);
trx.commit();
session.close();
}
public void update(T entity) {
Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
Transaction trx = session.beginTransaction();
session.update(entity);
trx.commit();
session.close();
}
}
Server adding logic. First of all, I save it to the database, then fill the Set with users and execute update()
This works if the table with users is empty, all necessary records and connections are created in the Server_Users and Users tables:
public static void addServer(Guild guild) {
Server server = new Server(Long.parseLong(guild.getId()), guild.getName());
serverDAO.save(server);
for (Member m : guild.getMembers()) {
User user = new User(Long.parseLong(m.getId()), m.getUser().getName());
user.addServer(server);
server.addUser(user);
}
serverDAO.update(server);
}
I found a solution
#Cascade({
org.hibernate.annotations.CascadeType.SAVE_UPDATE,
org.hibernate.annotations.CascadeType.MERGE,
org.hibernate.annotations.CascadeType.PERSIST
})
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "server_users",
joinColumns = #JoinColumn(name = "server_sn"),
inverseJoinColumns = #JoinColumn(name = "user_sn")
)
private Set<User> users = new HashSet<>();
I added CascadeTypes SAVE_UPDATE, MERGE and PERSIST to Server and User code
In addition, I redesigned the architecture of the base, making snowflakes as Primary Keys, because values are always unique

JPA mappedBy reference an unknown target entity

I am writing a simple inventory database that contains tables for products, orders and customers. The database definition can be found here:
CREATE TABLE public.customers
(
id integer NOT NULL DEFAULT nextval('customers_id_seq'::regclass),
title character varying(10) COLLATE pg_catalog."default" NOT NULL,
first_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
middle_names character varying(50) COLLATE pg_catalog."default",
last_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
email character varying(50) COLLATE pg_catalog."default" NOT NULL,
phone_number character varying(50) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT customers_pkey PRIMARY KEY (id)
)
CREATE TABLE public.products
(
id integer NOT NULL DEFAULT nextval('products_id_seq'::regclass),
name character varying(100) COLLATE pg_catalog."default" NOT NULL,
sku integer NOT NULL,
inventory_on_hand integer NOT NULL,
reorder_threshold integer NOT NULL,
price numeric(5,2),
inventory_to_be_shipped integer NOT NULL,
CONSTRAINT products_pkey PRIMARY KEY (id)
)
CREATE TABLE public.order_items
(
id integer NOT NULL DEFAULT nextval('order_items_id_seq'::regclass),
product_id integer NOT NULL,
order_id integer NOT NULL,
CONSTRAINT order_items_pkey PRIMARY KEY (id),
CONSTRAINT order_items_order_id_fkey FOREIGN KEY (order_id)
REFERENCES public.orders (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT order_items_product_id_fkey FOREIGN KEY (product_id)
REFERENCES public.products (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
CREATE TABLE public.orders
(
id integer NOT NULL DEFAULT nextval('orders_id_seq'::regclass),
customer_id integer,
order_date date NOT NULL DEFAULT now(),
arrival_date date,
CONSTRAINT orders_pkey PRIMARY KEY (id),
CONSTRAINT orders_customer_id_fkey FOREIGN KEY (customer_id)
REFERENCES public.customers (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
I am trying to implement a Spring Security Resource server to perform CRUD operations on the database. I have implemented entity classes for each table in the database but when try to start the server I get a
org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: edu.finalyearproject.imsresourceserver.models.Order.customers in edu.finalyearproject.imsresourceserver.models.Customer.orders
My entity and repository classes can be found below:
Product.java:
#Entity
#Table(name = "products")
#Data
public class Product
{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer sku;
private Float price;
private Integer inventory_on_hand;
private Integer reorder_threshold;
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
#JoinTable(
name = "order_items",
joinColumns = #JoinColumn(name = "product_id"),
inverseJoinColumns = #JoinColumn(name = "order_id")
)
private Set<Order> orders = new HashSet<>();
}
Customer.java
#Entity
#Table(name = "customers")
#Data
public class Customer
{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
private String title;
private String first_name;
private String middle_names;
private String last_name;
private String email;
private String phone_number;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Order> orders;
}
Order.java
#Entity
#Table(name = "orders")
#Data
public class Order
{
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name="customer_id", nullable=false)
private Customer customer;
private Date order_date;
private Date arrival_date;
#ManyToMany(mappedBy = "orders", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<Product> products = new HashSet<>();
}
I know the problem is related to the relationships between the entities, but I haven't been able to find a solution. Any help would be greatly appreciated.
Try to correct this:
#Entity
public class Customer
{
// ...
#OneToMany(mappedBy = "orders", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Order> orders;
}
to this:
#Entity
public class Customer
{
// ...
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Order> orders;
}
See additional explanation in the documentation.
And you should correct also your Product-Order #ManyToMany association. Only one side of this association should use #JoinTable other side should use mappedBy property of the #ManyToMany annotation. Something like this:
#Entity
public class Product
{
// ...
#ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.LAZY
)
#JoinTable(
name = "order_items",
joinColumns = #JoinColumn(name = "product_id"),
inverseJoinColumns = #JoinColumn(name = "order_id")
)
private Set<Order> orders = new HashSet<>();
}
#Entity
public class Order
{
// ...
#ManyToMany(
mappedBy = "orders",
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.LAZY)
private Set<Product> products = new HashSet<>();
}
As it is stated in the documentation:
For #ManyToMany associations, the REMOVE entity state transition doesn’t make sense to be cascaded because it will propagate beyond the link table. Since the other side might be referenced by other entities on the parent-side, the automatic removal might end up in a ConstraintViolationException.
Also as this is explained in this section of the documentation:
If you forget to JOIN FETCH all EAGER associations, Hibernate is going to issue a secondary select for each and every one of those which, in turn, can lead to N+1 query issues.
For this reason, you should prefer LAZY associations.

hibernate avoid duplicates in database

How to avoid duplicates in the database.
'1', 'Male'
'2', 'Male'
'3', 'Female'
to only save
'1', 'Male'
'2', 'Female'
or:
to only save
Countries
'1', 'UK'
'2', 'Brazil'
'3', 'China'
My database schema:
CREATE TABLE IF NOT EXISTS `bi_person` (
`id_person` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL,
`last_name` VARCHAR(100) NOT NULL,
`additional_info` VARCHAR(50) NOT NULL,
`gender_id` VARCHAR (50) UNIQUE REFERENCES bi_gender
) COLLATE='utf8_bin';
-- Table 'bi.gender`
CREATE TABLE IF NOT EXISTS `bi_gender` (
`id_gender` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(10) NOT NULL
) COLLATE='utf8_bin';
-- Table 'bi.country`
CREATE TABLE IF NOT EXISTS `bi_country` (
`id_country` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(10) NOT NULL
) COLLATE='utf8_bin';
I have models with relation many to many - person countries and one to many person-->gender
Model:
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id_book")
private Integer id;
#Column(name = "name")
private String name;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="bi_person_country", joinColumns=#JoinColumn(name="id_country"), inverseJoinColumns=#JoinColumn(name="id_person"))
private Set<Person> persons;
Model gender:
#Table(name = "bi_gender")
#Entity
public class Gender {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
private String name;
Person entity:
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id_person")
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "last_name")
private String lastName;
#Column(name = "additional_info")
private String additionalInfo;
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "persons")
private Set<Country> countries;
Adding person object:
Person person = Person();
Gender gender = new Gender();
gender.setGenderName(pepPersons.get(a).getGender());
gender = genderRepository.save(gender);
Country country = new Country();
country.setCountryName(pepPersons.get(a).getCountry());
country = countryRepository.save(country);
person.setName(pepPersons.get(a).getFirstName());
person.setLastName(pepPersons.get(a).getLastName());
person.setAdditionalInfo(pepPersons.get(0).getFunction());
person.setGender(gender);
Set<Country> countries = new HashSet();
countries.add(country);
person.setCountries(countries);
personRepository.save(person);
I would recommend to use unique index to prevent a duplicates in DB table.
In MySQL it could be done with statement:
CREATE UNIQUE INDEX ux_bi_gender_name
ON bi_gender(name);
It would guarantee uniqueness on DB Level.
Regarding Hibernate annotations:
As far as I know Hibernate doesn't make any check for uniqueness.
Based on Hibernate JavaDoc for #Column
This is a shortcut for the UniqueConstraint annotation at the table level and is useful for when the unique key constraint corresponds to only a single column. This constraint applies in addition to any constraint entailed by primary key mapping and to constraints specified at the table level.
and #UniqueConstraint
Specifies that a unique constraint is to be included in the generated DDL for a primary or secondary table.
So it is helpful if you are generating DB Schema with Hibernate as well as for documentation purposes.
You will have to declare that column as unique : #Column(unique = true)
If I understand you correctly, the country and gender tables are master data, containing unique countries and genders respectively.
In that case you do not need cascade, in application fetch the required gender set it on person and persist person. remove the cascade = CascadeType.ALL
update
Gender male = genderRepository.findByName("Male");
person.setGender(male);
...
personRepository.save(person)
#Column(name = "name",unique = true, nullable=false)
private String name;
use this in entity to avoid the duplicate name

Hibernate - Crash with 2 #OneToMany

Hibernate crashes when using more than one #OneToMany entries in my Users.entity and I don't understand why.
I have a table for users (primary key userID) and various other tables which refer to the primary key userID by a foreign key set in database (InnoDB set and foreign key is set in each depending table).
Here an example with three tables:
Table users:
CREATE TABLE `users` (`userID` int(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `users` ADD PRIMARY KEY (`userID`);
Table: vacationrequests
CREATE TABLE `vacationrequests` (`requestID` int(11) NOT NULL,`userID` int(4) NOT NULL,) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `vacationrequests` ADD CONSTRAINT `userID` FOREIGN KEY (`userID`) REFERENCES `users` (`userID`) ON UPDATE CASCADE; COMMIT;
Table monthend:
CREATE TABLE `monthend` (`monthendID` int(11) NOT NULL,`userID` int(4) NOT NULL,) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Entity Users:
#Entity
#Table(name="users")
public class Users {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="userID")
private int userID;
... .... (other variables)
#OneToMany(fetch = FetchType.LAZY, mappedBy="monthend")
private Set<Monthend> monthend;
#OneToMany(fetch = FetchType.LAZY, mappedBy="vacationrequests")
private Set<Vacationrequests> vacationrequests;
public Users() {
}
Entity Vacationrequests:
#Entity
#Table(name="vacationrequests")
public class Vacationrequests {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="requestID")
private int requestID;
... .... (other variables)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="userID", nullable = false)
private Users users;
public Vacationrequests() {
}
Entity Monthend:
#Entity
#Table(name="monthend")
public class Monthend {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="monthendID")
private int monthendID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="userID", nullable = false)
private Users users;
#Column(name="clientID")
private int clientID;
#Column(name="month")
private int month;
#Column(name="year")
private int year;
#Column(name="monthend")
private int monthend;
public Monthend() {
}
Working Query:
List<Object> listJoinUsersMonthend = session.createQuery("from Monthend m inner join m.users as users where m.clientID = :clientID AND m.year = :year AND users.loginclass = 0 AND users.isactive = 1 AND m.monthend = 0 AND m.month < :month order by users.userID asc")
.setInteger("clientID", user.getClientID())
.setInteger("year", year)
.setInteger("month", month)
.getResultList();
This second query i would like to integrate:
List<Object> listJoinVacationrequestsUsers = session.createQuery("from Vacationrequests v inner join v.users as users where v.clientID = :clientID AND v.approved=0 AND v.vacationtype=1 AND YEAR(v.startdate) = :year" )
.setInteger("clientID", user.getClientID())
.setInteger("year", year)
.getResultList();
Everything works fine with just one query and one entry in the Users.entity. As soon as I add the two entries hibernate just crashes and there is no error message. Is it not possible to do two #OneToMany statements in a entity ?
It seems that the problem is in the mapping of the associations in the Users entity.
You should change the mappedBy attribute of the associations to specify the field name that references the current entity in the associated one (in this case users), like this:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "users")
private Set<Monthend> monthend;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "users")
private Set<Vacationrequests> vacationrequests;

What is the best way to map data of junction table in Java entity?

I have three tables which presents my very simple project.
CREATE TABLE company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(250) NOT NULL
);
CREATE TABLE employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(250) NOT NULL
);
CREATE TABLE company_employee (
company_id INT NOT NULL,
employee_id INT NOT NULL,
hire_date DATE DEFAULT NULL,
resign_date DATE DEFAULT NULL,
FOREIGN KEY (company_id) REFERENCES company (id),
FOREIGN KEY (employee_id) REFERENCES employee (id)
);
And I have Java representation
#Entity
#Table(name = "employee")
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
#Column(name = "name")
String name;
#ManyToMany(mappedBy = "employees")
private List<Company> companies;
#Entity
#Table(name = "company")
public class Company implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "name")
private String name;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "company_employee",
joinColumns = {#JoinColumn(name = "company_id")},
inverseJoinColumns = {#JoinColumn(name = "employee_id")})
private Collection<Employee> employees;
I can't figured out where I can store history data. In history data I need to store hire_date, resign_date of emplyee and to store all companies of each emplyee as well. So my question is haw can I manage such infortation and what is the best way to store all that history info?
That is a many to many relationship with attributes. I am sure you will be able to understand who to deal with it with one basic example:
http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/
You have already an intersection table "company_employee".
You can store here employee1 1.1.2013 to 31.12.2013 # company1. And an other time 1.1.2014 ... 31.12.2014 # company2.
You have to order by hire_date desc. Per defenition the first value in the list is the current or last employment and all other are consindert as history.
It's not a matter of where to store but how to read the data.

Categories