OneToMany issue in hibernate - java

I have models like this:
#Table(name="EMPLOYEE")
public class Employee {
#Column(name="firstname")
private String firstname;
// and others
#ManyToOne( targetEntity = Employee.class,
fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="department_id",
insertable=false, updatable=false,
nullable=false)
private Department department;
=============================================================================
#Table(name="DEPARTMENT")
public class Department {
#Column(name="DEPARTMENT_ID")
private Long departmentId;
#OneToMany( targetEntity = Employee.class,
fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="department_id")
#IndexColumn(name="idx")
private List<Employee> employees;
and my DepartmentDaoImpl is
public class DepartmentDaoImpl implements DepartmentDao{
#Autowired
private SessionFactory sessionFactory;
#Transactional
public void addDepartment(Department department) {
sessionFactory.getCurrentSession().save(department);
}
when i run project this exception appear in output
org.hibernate.MappingException: Unknown entity: org.springmvc.form.Department
what is this problem and how solved it?
Department department = new Department();
department.setDepartmentName("Sales");
department.setDepartmentId(90);
Employee emp1 = new Employee("reza", "Mayers", "101",department.getDepartmentId());
// Employee emp2 = new Employee("ali", "Almeida", "2332");
department.setEmployees(new ArrayList<Employee>());
department.getEmployees().add(emp1);

Many problems in this code.
First problem: Unknown entity: org.springmvc.form.Department. This means that Department is not annotated with #Entity and/or is not listed in the entities in the hibernate configuration file.
Second problem:
#ManyToOne( targetEntity = Employee.class)
private Department department;
This doesn't make sense. The target entity is obviously Department, not Employee. targetEntity is useless unless the type of the field is an abstract class or interface, and you need to tell Hibernat what it should use as concrete entity class. Otherwise, Hibernate know the target entity from the type of the field.
Third problem:
#OneToMany( targetEntity = Employee.class,
fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name="department_id")
This OneToMany is the inverse side of the bidirectional association that you have already declared and mapped in Employee. So you MUST NOT repeat the mapping here. Instead, you MUST declare it as the inverse side, using the mappedBy attribute:
#OneToMany(mappedBy = "department", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#IndexColumn(name="idx")
private List<Employee> employees;
Using eager fetching for a toMany association is a really bad idea as well. You really don't want to load the 200 employees of a department every time you load a department. That will kill the performance of your application.

Related

Multiple representation of child entity in parent entity

I'm curious if it is possible to have several #ManyToOne relations of same entity in parent entity with JPA/Hibernate.
Example:
I have bank transactions, each transaction has a BankPartner in tow roles Creditor and Debtor. The point is, I want to edit data only once. BankPartner with nickName "mistress" is only one :), doesn't matter if in role creditor or debtor. Once, it will be renamed to wife, so I don't want to change separately. Also, the Balance is SUM of all transactions for BankPartner in both roles.
#Entity
public class Transaction {
..
#ManyToOne(fetch = FetchType.LAZY, cascade={CascadeType.ALL}, orphanRemoval=true, targetEntity = PartnerEntity.class)
#JoinColumn(name = "CREDITOR_ID")
private BankPartner creditor
#ManyToOne(fetch = FetchType.LAZY, targetEntity = PartnerEntity.class)
#JoinColumn(name = "DEBTOR_ID")
private BankPartner debtor
..
}
#Entity
public class BankPartner {
...
private String name;
private String nickName;
private String description;
...
}
I can imagine that from "Transaction" direction in can somehow work, but can't find a way to work from BankPartner direction.
I can see two different approaches
create #ManyToMany with "ROLE_TYPE" in intersection table between BankPartner and Transaction
create two separate entities Debtor an Creditor from the same table.
But, as I said, I'm curios about the first approach ..
You can use a multi column join as such:
#Entity
public class Transaction {
#ManyToOne(fetch = FetchType.LAZY, cascade={CascadeType.ALL}, orphanRemoval=true, targetEntity = PartnerEntity.class)
#JoinColumns({
#JoinColumn(name = "DEBTOR_ID"),
#JoinColumn(name = "CREDITOR_ID")
})
private BankPartner partner
}

How to manage OnetoOne inserting data in child only

I am very new to hibernate and I am working with JPA and Hibernate4. Trying to insert parent object in child as onetoone relationship.
I went through some tutorials but All the example in the web shows, inserting both parent and child tables.
I want to insert data in child table only.
I have two tables called user and department.
User table consists of user details with department as onetoone relationship, as follows,
#Entity
#Table(name = "User")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentId")
private Department departmentId;
// getters and setters...
}
Below is my Department entity,
#Entity
#Table(name = "Department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "name")
private String name;
// getters and setters...
}
In department table there is only 4 data. I want to insert data only in user data while insert into it and don't want to insert in Department.
How can I do that.Please assist.
You have to use mappedBy for this, as mentoned below in child Table, Department in your case
#OneToOne(mappedBy="department")
private UserEntity user;
These posts explain you better this,
JPA JoinColumn vs mappedBy
Understanding mappedBy annotation in Hibernate
You need to specify the relationship owner using mappedBy property in the OneToOne mapping in the owner side, here in your case in the Department class, you should add:
#OneToOne(mappedBy="department")
private UserEntity user;
I updated your code, to included the stated annotation and also renamed the Department property in your UserEntity class from departmentId to department to avoid confusion between relationship owner and its id:
#Entity
#Table(name = "User")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentId")
private Department department;
// getters and setters...
}
Below is the Department entity,
#Entity
#Table(name = "Department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "name")
private String name;
#OneToOne(mappedBy="department")
private UserEntity user;
// getters and setters...
}
This will give you the right mapping with the expected behaviour.
In the #OneToOne annotation, the default value for parameter optional is true. So your annotation is the same as #OneToOne(fetch = FetchType.EAGER, optional = true). This means you can simply leave the Department in a UserEntity instance empty. In that case, persisting it results in persisting only a user entity and no department.
Even if you created a Department instance and assigned it to a UserEntity instance, persisting the UserEntity would not automatically persist the Department, since you don't have any cascade parameter in your annotation. If you don't automatically cascade persists, you would have to persist the Department first and then persist the corresponding user entity.
Maybe you're asking about using existing departments for your user entities. In that case, you first need to get the department via Hibernate (or the JPA API) from an entity manager. The entity instance you get is managed by Hibernate, and you can then set it in a UserEntity and persist that, to have it refer to the department.
Finally, I think one department will probably have more than one user. It might make more sense to have a #ManyToOne annotation instead of #OneToOne, indicating multiple users can refer to the same department, but that depends on your domain model.

How to extend JPA entity to just add composition

I have a concrete class for Employee entity. Employee is persisted by other application, I'm just using the data. I want to extend Employee to add properties that are other Entities using composition. I don't need to persist a child entity per se, but only the entities I'm trying to extend to Employee with using composition. Here is some code to help clear things up.
#Entity
#Table(name = "Legacy_Table_Name", schema = "another_owner")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "emp_id")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String emp_id;
private String firstName;
etc...
-
public class EnhancedEmployee extends Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Transient
private SomeEntity someCompositionProperty;
#OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
private Collection<AnotherEntityWithItsOwnTable1> list1;
#OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
private Collection<AnotherEntityWithItsOwnTable2> list2;
If I make EnhancedEmployee an entity then JPA tries to create/use an EnhancedEmployee database table (right now in dev so I'm using create-drop persistence.xml property). If I remove the #Entity annotation from EnhancedEmployee, JPA complains that EnhancedEmployee is not an Entity in other classes where I want to utilize these extra properties
#ManyToMany(cascade = CascadeType.MERGE)
#LazyCollection(LazyCollectionOption.FALSE)
#JoinTable(name = "PARTICIPATING_EMPLOYEES", joinColumns = { #JoinColumn(name = "event_id") }, inverseJoinColumns = { #JoinColumn(name = "emp_id") })
private Collection<EnhancedEmployee > participants;
All I'm trying to do is reference an Employee setter getters for these extra properties whether or not they have data persisted for these extra properties.
I realize I could probably just modify my Employee class and add someCompositionProperty and list1/2 relations to that class but doesn't that then violate https://en.wikipedia.org/wiki/Open/closed_principle. While my Employee entity class is the "same" for all my projects the source code is really part of each project's package so perhaps the open/closed doesn't apply here and I should just modify the Employee entity class
If I make EnhancedEmployee an entity then JPA tries to create/use an
EnhancedEmployee database table (right now in dev so I'm using
create-drop persistence.xml property).
You could avoid this by changing the inheritance type to SINGLE_TABLE
Also your discriminator column emp_id seems to me like a bad choice. Better change it to something like #DiscriminatorColumn(name = "TYPE") because emp_id is the primary key and and cannot repeat itself in a table. Also your EnhancedEmployee needs #DiscriminatorValue(value = "ENHANCED")

Annotation to join columns with OR condition instead of AND condition

I have 2 java classes, Relation and Person, which both are present in my database.
Person:
#Entity
#Table(name = "persons")
public class Person {
#Id
#Column
private int id;
#Column
private String name;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "slave_id", referencedColumnName="id"),
#JoinColumn(name = "master_id", referencedColumnName="id")
})
private List<Relation> relations;
//Getters and setters
}
Relation:
#Entity
#Table(name = "relations")
public class Relation {
#Id
#Column
private int id;
#Column
private int child_id;
#Column
private int parent_id;
#Column
private String type;
//Getters and setters
}
Each Person has a list of relations (or not), the relation should be added to the list when the child_id or the parent_id of the relation is equal to the id of the person.
TL;DR:
When relation.child_id OR relation.parent_id = person.id => add relation to list of relations to the person
The issue I am facing is that this annotation:
#JoinColumns({
#JoinColumn(name = "child_id", referencedColumnName="id"),
#JoinColumn(name = "parent_id", referencedColumnName="id")
})
creates following SQL (just the necessary part):
relations relations6_
on this_.id=relations6_.slave_id
and this_.id=relations6_.master_id
What is the correct annotation in Java Hibernate to generate an SQL statement saying OR instead of AND
Some of the options that you could utilize:
Database views. Create the view that does custom join for you and map the entity to the view.
Join formula. I managed to make them work only on many-to-one associations. Nevertheless, you could make the association bidirectional and apply the formula in the Relation entity.
#Subselect. This is a kind of Hibernate view, suitable if you can't afford to create a real database view or change the db schema to better suit the entity model structure.
This and this answer could also be helpful.
Also, you can always use two separate associations for slaves and masters:
public class Person {
#OneToMany
#JoinColumn(name = "slave_id"),
private List<Relation> slaves;
#OneToMany
#JoinColumn(name = "master_id"),
private List<Relation> masters;
public List<Relation> getRelations() {
List<Relation> result = new ArrayList<>(slaves);
result.addAll(masters);
return result;
}
}
However, keep in mind that joining all of them in a single query requires full Cartesian product between masters and slaves.
You can use #FilterDef and #Filter annotations.

Persistence: ManyToMany to same class

I am trying to set a ManyToMany annotation on my code:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "user")
public class User extends AbstractUser
{
#ManyToMany(mappedBy = "promotors", cascade = CascadeType.PERSIST)
#JoinTable(name = "user_student",
joinColumns=#JoinColumn(name="promotor_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="student_id", referencedColumnName="id")
)
private Collection<User> students;
#ManyToMany
private Collection<User> promotors;
}
However every time i try to run the application and the db gets generated, it creates 2 tables for the ManyToMany, 1 new table that is called user_student as i defined beneath, but it also creates a second table user_user which i didn't define but is generated from the promotors.
It's correct you cannot map many to many relationship on one table. As you have only one possible column to map it to. What enforces one to one relationship.
You always have to have mapping table. Its also most convenient way to map many to many relationships on different tables.
Apparently, i didn't define the second ManyToMany correctly, this is the correct code:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "user")
public class User extends AbstractUser
{
#ManyToMany
#JoinTable(name = "user_student",
joinColumns={#JoinColumn(name="promotor_id", referencedColumnName="id")},
inverseJoinColumns={#JoinColumn(name="student_id", referencedColumnName="id")}
)
private Collection<User> students;
#ManyToMany(mappedBy = "students", cascade = CascadeType.PERSIST)
private Collection<User> promotors;
}

Categories