Why entityManager.contains returns different results? - jpa

This is in JPA2 (EclipseLink) and JSF2.
I have an entity class Student:
#Entity
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstname;
private String lastname;
private int age;
public Student(String firstname, String lastname, int age) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
public Student() {
}
// accessors and mutators here
}
Session bean StudentFacade that inherits AbstractFacade:
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public T edit(T entity) {
return getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
// other methods: findAll, findRange, count
}
#Stateless
public class StudentFacade extends AbstractFacade<Student> {
#PersistenceContext(unitName = "jpa2testsPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public StudentFacade() {
super(Student.class);
}
public boolean contains(Student s) {
return getEntityManager().contains(s);
}
public void testContains() {
Student s = find(1L);
boolean isContains = getEntityManager().contains(s);
}
}
This is my JSF Managed Bean:
#ManagedBean
#RequestScoped
public class IndexController {
#EJB
private StudentFacade studentFacade;
/**
* Creates a new instance of IndexController
*/
public IndexController() {
}
public String test() {
Student s = new Student("John", "Doe", 20);
studentFacade.create(s);
Student s1 = studentFacade.find(1L); // This works because table only has 1 record
boolean isContains = studentFacade.contains(s);
return null;
}
}
When I run test() from managed bean, isContains is false. But when testContains() in StudentFacade is called, isContains is true. Why is this?

StudentFacade is a Stateless Session Bean (SSB). The contents of its instance variables are not guaranteed to be preserved across method calls (reference). It's like having a different instance of EntityManager created for each method invocation.
When you run your test from the managed bean, you invoke two different methods on the SSB, therefore a different EntityManager instance is created for each call, and the second one does not contain the Student instance because it has not been loaded yet.
But when you run your test inside a method of the SSB itself, the same EntityManager is used for the scope of the entire method, therefore the call to contains() returns true.

Related

JPA #ManyToOne does not working

I can't understand where I'm going wrong when saving a List within and JPA Entity.
I have a super class Person. Client class extends Person. Client class has a list of Phone entities as #OneToMany (Bidirection) as code shown below. Whenever a Client entity is persisted with that phone list, all phones in list are saved as well. However, in Phone Table there are no client id recorded.
#Entity#Inheritance(strategy=InheritanceType.SINGLE_TABLE)#DiscriminatorColum(name="type")
public abstract class Person implements Serializable {
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.SEQUENCE,generator="PERSON_SEQ")
#SequenceGenerator(name="PERSON_SEQ",sequenceName="PERSON_SEQ", allocationSize=1,initialValue=1000)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}}
Client.class
public class Client extends Person implements Serializable {
private static final long serialVersionUID = 1L;
private String foo;
#OneToMany(cascade=CascadeType.ALL,mappedBy="owner")
private List<Phone> phones;
public List<Phone> getPhones() {
return phones;
}
public void setPhones(List<Phone> phones) {
this.phones = phones;
}
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
Phone class
public class Phone implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long idPhone;
private String number;
#ManyToOne(fetch=FetchType.EAGER) #JoinColumn(name="id")
private Person owner;
public Long getIdPhone() {
return idPhone;
}
public void setIdPhone(Long idPhone) {
this.idPhone = idPhone;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
}
ClientController class
#Named(value = "clientController")
#ViewScoped
public class ClientController extends BaseController implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Inject
private ClientService service;
#Inject
private Client client;
#Inject
private Employee employee;
#Inject
private Phone phone;
public void save(ActionEvent event) {
System.out.println(" Saving in Controller");
try {
client = new Client();
employee = new Employee();
Phone p1 = new Phone();
p1.setNumber("99998888");
Phone p2 = new Phone();
p2.setNumber("88887777");
List<Phone> phones = new ArrayList<Phone>();
phones.add(p1);
phones.add(p2);
client.setName("Novembro" );
client.setPhones(phones);
employee.setPhones(phones);
client.setFoo("foo value" );
employee.setBar("bar value");
service.saveOrUpdate(client);
//client = new Client();
addMessage(FacesMessage.SEVERITY_INFO, "Cliente registrado com sucesso");
} catch (Exception e) {
addMessage(FacesMessage.SEVERITY_ERROR, "Tente mais tarde");
e.printStackTrace();
}
}
}
Client Service class
public class ClientService implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Inject
private ClientDAO dao;
public Client saveOrUpdate(Client client) {
System.out.println(" Saving in Service");
return dao.save(client);
}
}
DAO save method
public T save(T entity) {
beginTransaction();
em.persist(entity);
em.flush();
commitAndCloseTransaction();
return entity;
}
I can't understand why it is not working as expected. I mean, save phones entities with ID from Client who owns the phones.
Database Postgresql 9.6
EclipseLink 2.6.0
JPA 2.1
All classes have #Entity and #Discrimator annotations
#Entity
#DiscriminatorValue(value="C")
#Entity
#Table(name="PHONE")

JPA generates negative sequence values generated for ID

I am creating a CRUD web application using JPA.
Technically every thing is working fine (no errors at all), but when checking my database I noticed that the after adding a new entry to my table, the ID generated from a sequence is a negative value: -46, -45, -44, etc ...
Here are the relevant parts of my code :
My entity :
#Entity
#NamedQuery(name="Book.findAll", query="SELECT b FROM Book b")
#SequenceGenerator(name="ma_seq", sequenceName="book_seq")
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ma_seq")
#Id private long id;
private String auteur;
private String langue;
private String titre;
public Book() {
}
//...getters and setters
}
My DAO :
public class MyDAO {
//Constructeur
public MyDAO(){
}
#PersistenceContext
private EntityManager em;
#Resource
private UserTransaction userTransaction;
public EntityManager getEm() {
return em;
}
public void setEm(EntityManager em) {
this.em = em;
}
#Transactional
public void register(Book livre) throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException {
// Save employee
userTransaction.begin();
this.em.persist(livre);
userTransaction.commit();
}
//other fonctions
}
after adding this to #SequenceGenerator then working fine!!!
allocationSize = 1

Could not create stateless EJB with JPA

I'm trying to insert some data to DB with EJB and JPA. When I execute the code i got the serverError: class javax.faces.el.EvaluationException javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB error. Here my code. I have try lot of by changing various things. what is that error occurred? I think my Entity manager initialization has some wrong
DesignationEntity de = new DesignationEntity();
de.setDesignationName(this.designationName);
de.setDesignationDescription(this.designationDescription);
ds.addDesignationDb(de);
EJB service class
#Stateless
#LocalBean
public class DesignationService {
#PersistenceUnit(unitName = "ecs2complainmanager")
private EntityManager em;
public DesignationService() {
}
public void addDesignationDb(DesignationEntity de){
em.persist(de);
}
}
Entity class
#Entity
public class DesignationEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Integer designationId;
private String designationName;
private String designationDescription;
#OneToOne(mappedBy = "designationId")
private UserEntity user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getDesignationId() {
return designationId;
}
public void setDesignationId(Integer designationId) {
this.designationId = designationId;
}
public String getDesignationName() {
return designationName;
}
public void setDesignationName(String designationName) {
this.designationName = designationName;
}
public String getDesignationDescription() {
return designationDescription;
}
public void setDesignationDescription(String designationDescription) {
this.designationDescription = designationDescription;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
}
#PersistenceUnit is the cause. After I changed it to #PersistenceContext

How to use #IdClass annotation with composite key

Someone could please share an example of two entities working on a Master-Detail pattern for EclipseLink (JPA 2.1) using composite key with #IdClass
Here is the example from the documentation
public class EmployeePK implements Serializable {
private long empId;
private long department;
public EmployeePK() {
}
public long getEmpId() {
return this.empId;
}
public void setEmpId(long empId) {
this.empId = empId;
}
public long getDepartment() {
return this.department;
}
public void setDepartment(long department) {
this.department = department;
}
public int hashCode() {
return (int)this.empId.hashCode();
}
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof EmployeePK)) return false;
EmployeePK pk = (EmployeePK) obj;
return pk.empId.equals(this.empId) && pk.department.equals(this.department);
}
}
and
#IdClass(EmployeePK.class)
#Entity
public class Employee implements Serializable{
#Id
long empId;
#Id
#ManyToOne
Department department;
...
}

Entity Manager: em.merge() creates a new record instead of updating

I was developing an EJB application using netbeans which manages Hotel Bookings. I realised that the em.merge() function of the Entity manager inserts a new record in the database instead of updating if the primary key or the #Id of the entity is set to autogenerated.
I have two entities - Booking and Room. The ID for Booking is autogenerated whereas for Room its not autogenerated. The same merge() function in the session bean inserts a new row for Booking but updates for Room.
My Entity beans and session beans are as follows:-
Booking Entity
#SequenceGenerator(name="booking_seq", initialValue=1, allocationSize=100)
#Entity
#NamedQueries({#NamedQuery(name="Booking.getAll",query="SELECT e FROM Booking e order by e.bookingId")})
public class Booking implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="booking_seq")
#Column
private int bookingId;
#Column
private int roomId;
#Column
private int customerId;
#Column
#Temporal(javax.persistence.TemporalType.DATE)
private Date arrival_date;
#Column
#Temporal(javax.persistence.TemporalType.DATE)
private Date departure_date;
public Booking(int bookingId, int roomId, int customerId, Date arrival_date, Date departure_date) {
this.bookingId = bookingId;
this.roomId = roomId;
this.customerId = customerId;
this.arrival_date = arrival_date;
this.departure_date = departure_date;
}
public Booking() {
}
public int getBookingId() {
return bookingId;
}
public void setBookingId(int bookingId) {
this.bookingId = bookingId;
}
public int getRoomId() {
return roomId;
}
public void setRoomId(int roomId) {
this.roomId = roomId;
}
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public Date getArrival_date() {
return arrival_date;
}
public void setArrival_date(Date arrival_date) {
this.arrival_date = arrival_date;
}
public Date getDeparture_date() {
return departure_date;
}
public void setDeparture_date(Date departure_date) {
this.departure_date = departure_date;
}
}
Room Entity
#Entity
#Table
#NamedQueries({#NamedQuery(name="Room.getAll",query="SELECT e FROM Room e order by e.roomId")})
public class Room implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column
private int roomId;
#Column
private String roomType;
#Column
private String bedType;
#Column
private double tariff;
public Room() {
}
public Room(int roomId, String roomType, String bedType, double tariff) {
this.roomId = roomId;
this.roomType = roomType;
this.bedType = bedType;
this.tariff = tariff;
}
public int getRoomId() {
return roomId;
}
public void setRoomId(int roomId) {
this.roomId = roomId;
}
public String getRoomType() {
return roomType;
}
public void setRoomType(String roomType) {
this.roomType = roomType;
}
public String getBedType() {
return bedType;
}
public void setBedType(String bedType) {
this.bedType = bedType;
}
public double getTariff() {
return tariff;
}
public void setTariff(double tariff) {
this.tariff = tariff;
}
}
The session bean for Booking Entity
#Stateless
public class BookingDAO implements BookingDAOLocal {
#PersistenceContext
private EntityManager em;
#Override
public void addBooking(Booking booking) {
em.persist(booking);
}
#Override
public void editBooking(Booking booking) {
em.merge(booking);
}
#Override
public void deleteBooking(int bookingId) {
em.remove(em.find(Booking.class, bookingId));
}
}
The session bean for Room Entity
#Stateless
public class RoomDAO implements RoomDAOLocal {
#PersistenceContext
private EntityManager em;
#Override
public void addRoom(Room room) {
em.merge(room);
em.flush();
}
#Override
public void editRoom(Room room) {
em.merge(room);
em.flush();
}
#Override
public void deleteRoom(int roomId) {
em.remove(em.find(Room.class, roomId));
}
}
Actually i got the answer now. For the editBooking() method i was using the same code as addBooking(). In addBooking() i didnt have the setBookingId() method call as it was autogenerated. Just needed to add the extra part for edit method.
else if ("Add".equalsIgnoreCase(action) || "Edit".equalsIgnoreCase(action) )
{
try {
arrival_date = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH).parse(request.getParameter("arrival_date"));
departure_date = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH).parse(request.getParameter("departure_date"));
}
catch(ParseException e) {
e.printStackTrace();
}
Booking booking = new Booking();
if("Edit".equalsIgnoreCase(action))
{
int bookingId=Integer.parseInt(request.getParameter("bookingId"));
booking.setBookingId(bookingId);
}
booking.setRoomId(Integer.parseInt(request.getParameter("roomId")));
booking.setCustomerId(customerId);
booking.setArrival_date(arrival_date);
booking.setDeparture_date(departure_date);
if("Add".equalsIgnoreCase(action))
bookingDao.addBooking(booking);
else
bookingDao.editBooking(booking);
request.setAttribute("allBookings", bookingDao.getAllBookings());
request.getRequestDispatcher("booking_details.jsp").forward(request, response);
}
You are not trying to updating the record, you re trying to persisting the same room instead of try this.
#Override
public void editRoom(Room room) {
Room r-= em.merge(room);
r.setRoomType("2bed"); // your own update field other than the #Id (Primary key)
em.flush();
// you can retun the updated employee.
}