How implement Many-To-One relation with JPA, Spring MVC and eclipselink? - jpa

Formally I had used Hibernate and all was fine! Now I use Spring MVC with JPA and eclipselink. Generating independant Entities from Tables with org.eclipse.persistence.jpa.modelgen.processor (vers 2.7.10) is ok including static MetaModel. I can fetch single entities via spring-repository (extending CrudRepository).
But joining to other entities doesn't work. (The code is generated from table bestellung by eclipse modelgen):
#Entity
#Table(name="bestellung")
#NamedQuery(name="Bestellung.findAll", query="SELECT b FROM Bestellung b")
public class Bestellung implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Date abschluss;
private String bearbeiter;
private Date bestdat;
private Integer kundeId;
.... getter and setter following.
I am missing:
private Kunde kunde; // relation to table Kunde
or in entity Kunde:
private List<Bestellung> bestellung; // One-To-Many to Bestellung
In Hibernate it was possible to lazy-fetch it. Manipulating the generated code blocks the eclipse and makes no sense!
What can I do to generate the entities with suitable code?

Related

JPA: Update mapping table alone

I have a Project and Employee entities, which has ManyToMany relationship like below.
#Entity
public class Project {
#Id #GeneratedValue
private int projectId;
private String projectName;
// has some additional columns
#ManyToMany(mappedBy = "projects")
private List<Employee> emp = new ArrayList<Employee> ();
....
.....
}
#Entity
public class Employee {
#Id #GeneratedValue
private int id;
private String firstName;
private String lastName;
#ManyToMany(cascade=CascadeType.ALL)
List<Project> projects = new ArrayList<Project> ();
....
....
}
When I use above entities, JPA create a mpping table 'Employee_Project' like below.
create table Employee_Project (emp_id integer not null, projects_projectId integer not null)
My question is, whenever new employee is added, I want to update both employee table and Employee_Project mapping table only, assume I know project id that I would like to map this employee to. (without touching project table/entity, I mean why should I provide complete project object, while saving employee entity alone, how can I do this via jpa?)
You don't need to provide the entire Project object. Use EntityManager.getReference(projectId) or JpaRepository.getOne(projectId).
Those methods will create a proxy object with the appropriate id, rather than loading the entire Project entity from the data store.
EDIT Your service method should look pretty much like the following:
#Transactional
public void createEmployee(Employee employee, Long projectId) {
employee.setProjects(List.of(projectRepository.getOne(projectId));
employeeRepository.save(employee);
}
As a side note, CascadeType.ALL (in particular, because it includes CascadeType.MERGE and CascadeType.REMOVE) doesn't make sense for #ManyToMany. Unless you're planning to create a Project by creating an Employee, CascadeType.PERSIST makes no sense, either.

Generate JPA entities with wrapper classes instead of primitives in Eclipse

I'm currently using Eclipse Luna for J2EE Developers to generate JPA entities from a schema. The generated entities are being created with primitives (int) instead of wrappers (Integer) which is an issue for nullable fields. Is there a way to change this? There doesn't seem to be an option for it in the wizard and I have had no luck in my search so far.
Here is a snippet of a generated class as an example:
#Entity
#Table(name="facility")
#NamedQuery(name="Facility.findAll", query="SELECT f FROM Facility f")
public class Facility implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name="census_code")
private String censusCode;
#Temporal(TemporalType.TIMESTAMP)
private Date created;
private Timestamp modified;
private String name;
#Column(name="portal_id")
private int portalId;
#Column(name="short_name")
private String shortName;
...
}
Obviously id should remain a primitive but in this case portalId should be using the wrapper class.
Any suggestions are welcomed.

Avaje Ebean. ManyToMany deferred BeanSet

I am writing small app, using Play Framework 2.0 which uses Ebean as ORM.
So I need many-to-many relationship between User class and UserGroup class.
Here is some code:
#Entity
public class User extends Domain {
#Id
public Long id;
public String name;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Set<UserGroup> groups = new HashSet();
}
#Entity
public class UserGroup extends Domain {
#Id
public Long id;
public String name;
#ManyToMany(mappedBy="groups")
public Set<User> users = new HashSet();
}
Database scheme generator generates good scheme for that code with intermediate table and all work quite ok, till I using many-to-many.
So I am adding group in one request:
user.groups.add(UserGroup.find.byId(groupId));
user.update();
And trying output them to System.out in another:
System.out.println(user.groups);
And this returns:
BeanSet deferred
Quick search show that BeanSet is lazy-loading container from Ebean. But seems like it doesn't work in proper way or I missed something important.
So is there any ideas about what I am doing wrong?
You need to save associations manually
user.groups.add(UserGroup.find.byId(groupId));
user.saveManyToManyAssociations("groups");
user.update();

JPA #OneToMany Mapping Problem

I am trying to do do JPA/Hibernate mappings to map two tables, but am getting this error. any help would be greatly appreciated!!
Restaurants.java
#Entity
#Table(name="RESTAURANTS")
public class Restaurants{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy="restaurant")
private LinkedList<Menus> menus = new LinkedList<Menus>();
/* constructors **/
public Restaurants(){
this.dateJoined = new Date();
};
/* getters and setters **/
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy = "increment")
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
public LinkedList<Menus> getMenus() {return menus;}
public void setMenus(LinkedList<Menus> menus) {this.menus = menus;}
}
Menus.java
#Entity
#Table(name = "MENUS")
public class Menus {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private Long restaurantID;
#OneToMany
#JoinColumn(name="restaurant")
private Restaurants restaurant;
/* constructors */
public Menus(){}
/* getters and setters */
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy = "increment")
#Column(nullable = false)
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
public Long getRestaurantID() {return restaurantID;}
public void setRestaurantID(Long restaurantID) {this.restaurantID = restaurantID;}
public void setRestaurant(Restaurants restaurant) {this.restaurant = restaurant;}
public Restaurants getRestaurant() {return restaurant;}
}
With this error
Exception in thread "main" org.hibernate.MappingException: Could not
determine type for: bb.entities.Restaurants, at table: MENUS, for
columns: [org.hibernate.mapping.Column(restaurant)] at
org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:306) at
org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:290) at
org.hibernate.mapping.Property.isValid(Property.java:217) at
org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:464)
at org.hibernate.mapping.RootClass.validate(RootClass.java:235) at
org.hibernate.cfg.Configuration.validate(Configuration.java:1362) at
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1865)
at bb.TestMain.setUp(TestMain.java:26) at
bb.TestMain.main(TestMain.java:59)
Thanks.
It appears to be a misconception in the use of the #OneToMany annotation. The #OneToMany annotation is used to represent the 1-side in a 1:M relationship, and the inverse #ManyToOne relationship is used to represent the M-side. Therefore, a #OneToMany annotation should be defined on a collection-type in an entity and not on a normal reference type.
You should therefore:
use a #OneToOne association if that is the nature of the relationship between the entities.
or, decide which entity represents the 1-side in the 1:M relationship. Going by the use of the LinkedList class in Restaurants, I would consider the Restaurants class to be the 1-side, and use the #OneToMany annotation in the Restaurants class, while using the inverse #ManyToOne relationship in the Menus class. The refined code would be:
Restaurants.java
...
#OneToMany(mappedBy="restaurant")
private List<Menus> menus = new LinkedList<Menus>();
Menus.java
#ManyToOne
#JoinColumn(name="restaurant")
private Restaurants restaurant;
Note the change in the declaration of the menus member variable from LinkedList<Menus> to List<Menus>. Apparently, in this case, it is wiser to declare any collection with the interface-type of the collection, instead of the concrete collection class. The rationale is that the underlying JPA provider will use it's own concrete collection types at runtime, for the purpose of proxying the collection values. Hibernate for instance, will use a PeristentList at runtime, to represent the List in a managed entity, and not a LinkedList as created by the entity. If you use the concrete type, Hibernate might fail in mapping the column, or might fail in retrieving the associated records from the database; I'm not sure about the specifics of the runtime behavior, except that I know of the eventual failure.

Why JPA-2.0 Primary Key Classes have to implement Serializable but my example works without?

In many sources I have read PrimaryKey Classes and even JPA2 entities should be serializable.
IN my example (legacy database) there is a relationship between employee and languages:
Employee Class:
#Entity
#IdClass(EmpleadoId.class)
#Table(name = "NO_INFGRAEMPL")
public class Empleado {
#Id
#Column(name = "IGECOMPANIA", unique = true)
private String compania;
#Id
#Column(name = "IGENUMEROIDENTIFIC", unique = true)
private String numeroIdentificacion;
//...
}
Employee Compound PrimaryKey Class:
public class EmpleadoId {
private String compania;
private String numeroIdentificacion;
//...
}
Employee Language SKill Class:
#Entity
#IdClass(IdiomaEmpleadoId.class)
#Table(name = "NO_IDIOMEMPLE")
public class IdiomaEmpleado {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns(value = {
#JoinColumn(name= "IEMCOMPANIA", referencedColumnName = "IGECOMPANIA"),
#JoinColumn(name = "IEMEMPLEADO", referencedColumnName = "IGENUMEROIDENTIFIC")
})
private Empleado empleado;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "IEMIDIOMA")
private Idioma idioma;
#Column(name = "IEMNIVELLECTURA")
private String nivelLectura;
//...
}
Employee Language Skill Compound PrimaryKey Class:
public class IdiomaEmpleadoId {
private EmpleadoId empleado;
private String idioma;
//...
}
Language Class:
#Entity
#Table(name = "NO_IDIOMAS")
public class Idioma {
#Id
#Column(name = "IDICODIGO")
private String codigo;
#Column(name = "IDIDESCRIPCION")
private String descripcion;
//...
}
I am using EclipseLink JPA2 Provider under a J2SE application and it is not giving me any exceptions.
My questions are:
Why is it not giving me exceptions? Is it not enforced to have Serializable?
Is it safe to continue this way or should I definitely implemente serializable?.
In which ones?, JPA2 Entities or PrimaryKey Classes?
Thanks a lot for the help.
JPA specification contains such a requirement (JSR-317 secion 2.4 Primary Keys and Entity Identity):
The primary key class must be serializable.
If EclipseLink really doesn't enforce this requirement, it's an implementation detail of EclipseLink and I wouldn't recommend you to rely on it.
However, there are no requirements on serializability of entities, except for the following one which looks more like a recommendation than a requirement:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the
entity class must implement the Serializable interface.
Nothing is required to be serializable, but it seems it is requried by the spec (10x to axtavt) for primary keys, although there is no direct need for it.
Serialization is needed if the objects are transferred over-the-wire or persisted to disk, so I can't see the reason behind that decision. However, you should conform to it.
Primary key classes have to implement serializable and composite-ID class must implement serializable are two different questions.
I am going to answer you both, and hope it will help you to distinguish and understand holistically.
Primary key classes have to implement serializable:
Note: It could work without its iplementation also.
JPA specification contains such a requirement (JSR-317 secion 2.4 Primary Keys and Entity Identity):
The primary key class must be serializable.
However, there are no requirements on serializability of entities, so it's a recommendation than a requirement
exception:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface.
Composite-ID class must implement serializable.
The id is used as a key to index loaded objects in the session.
The session object needs to be serializable, hence all objects referenced by it must be serializable as well.
In case of CompositeIds the class itself is used as the id.