#OneToMany Entity Relationship not filling the list in the entity - jpa

I have asked a similar question these days, and after many many hours of trials and fails i find myself compelled to describe my problem from a different point of view.
So I have two entities, WaiterEntity and OrderEntity - as logic demands it, a waiter can have many orders, but an order just one waiter. When the method that persists orders is called, the given order is persisted correctly into the database. But when the waiter is asked about his orders with getOrders(), an empty list is returned. I tried to solve this like many tutorials tell, by (right after persisting the order) getting the list of orders from the waiter and adding the order to the list. Unfortunately there is very strange behaviour to observe: adding the line waiter.getOrders().add(order) somehow prevents or reverts the order to be persisted into the database. But when I try to get the waiter's orders, the all orders that previously were tried to persist appear correctly in the database, but at once the tables of WaiterEntity and OrderEntity become unreadable for JPA. (Although, I can still see the correct table contents through manually called SQL queries.) The only thing that helps is rebuilding the tables.
So maybe some properties of persistence.xml are wrong? The entity annotations are not correctly set up? Or the java code is invalid as I can't tell because I don't have much experience with JPA and GlassFish?
Here are the Entities:
#Entity
#XmlRootElement
#Table(name="WAITERENTITY")
public class WaiterEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.EAGER)
#JoinColumn(name = "waiter_id")
private List<OrderEntity> orders = new ArrayList<>();
... getters and setters
}
#Entity
#XmlRootElement
#Table(name="ORDERENTITY")
public class OrderEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long orderNumber;
#ManyToOne (cascade = CascadeType.ALL)
#JoinColumn (name = "table_id")
private TableEntity table_;
private int sumOfMoney = 0;
private boolean finalized = false;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private List<OrderItemEntity> orderItems = new ArrayList<>();
#ManyToOne (cascade = CascadeType.DETACH)
#JoinColumn (name = "waiter_id")
private WaiterEntity waiter;
... getters and setters
}
The method to create orders:
public void create(OrderEntity e) {
WaiterEntity waiter = null;
if (e.getWaiter() != null) {
waiter = em.find(WaiterEntity.class, e.getWaiter().getId());
if (waiter != null) e.setWaiter(waiter);
}
if (e.getTable() != null) {
TableEntity table = em.find(TableEntity.class, e.getTable().getId());
if (table != null) e.setTable(table);
}
em.persist(e);
if (waiter != null) {
waiter = em.find(WaiterEntity.class, e.getWaiter().getId());
//waiter.getOrders().add(e);
}
}
As mentioned, the commented line only makes problems. Further on, without this line, everything in the database is as it should be, as in the foreign keys are set up right, but an obtained WaiterEntity has an empty list, regardless that in fact it has orders in its relationship in the database.
edit: The method that gets a waiter's orders:
public List<OrderEntity> findOrdersByWaiter(#QueryParam("id") long id) {
WaiterEntity waiter = em.find(WaiterEntity.class, id);
return waiter.getOrders();
}
As mentioned, in the situation when the commented line above is un-commented, the strage behaviour starts when calling findOrdersByWaiter(waiter.getId()).
Furthermore, no exceptions are thrown by GlassFish. It's like it just does nothing anymore when calling persitence methods that work with the tables of WaiterEntity and/or OrderEntity.
It would really help if someone more experienced told me what I am doing wrong. If further explanation or code snippets are needed for a better understanding of the situation, I will paste it here. Thanks in advance!
edit 2: (#DonovanMuller) First, a little explanation why there are different object types: I use web resources. The client program and server program communicate using JSON. Only the server knows entity models and persists them. The client does the following (I am not posting all it's methods, just the relevant ones):
IWaiterWebAppClient client = new IWaiterWebAppClient();
client.create(new WaiterBean("John Marston"));
client.create(new WaiterBean("Abigail Marston"));
WaiterBean waiter = client.findByNameSingle(WaiterBean.class, "John Marston");
int rnd = (int) Math.round(Math.random() * 100);
client.create(new TableBean(rnd));
TableBean table = client.findByNameSingle(TableBean.class, String.valueOf(rnd));
OrderBean order = new OrderBean(waiter);
order.setWaiter(null);
client.create(order);
client.create(new OrderBean(waiter, table));
System.out.println(waiter.getName() + "'s OrderBeans:\n" + client.findOrdersByWaiter(waiter.getId()));
while client is an instance of:
public class IWaiterWebAppClient {
private final WebTarget webTarget;
private final Client client;
private static final String BASE_URI = "http://localhost:8080/iWaiter_WebAppServer/webresources";
public IWaiterWebAppClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget = client.target(BASE_URI).path("iwaiter");
}
public void close() {
client.close();
}
public <T> void create(T bean) {
webTarget.path(getResourcePath(bean.getClass()))
.request()
.post(Entity.entity(bean,MediaType.APPLICATION_JSON + ";charset=UTF-8"));
}
public <T> T findByNameSingle(Class<T> type, String name) {
List<T> list = findByName(type, name);
return (!list.isEmpty() ? list.get(0) : null);
}
public <T> List<T> findByName(Class<T> type, String name) {
return webTarget.path(getResourcePath(type) + "/findbyname/{name}")
.queryParam("name", name).request(MediaType.APPLICATION_JSON)
.get(constructGenericTypeArrayList(type));
}
public List<OrderBean> findOrdersByWaiter(long id) {
List<OrderBean> list = webTarget.path("order/findbywaiter/{id}")
.queryParam("id", id).request(MediaType.APPLICATION_JSON)
.get(new GenericType<ArrayList<OrderBean>>() {});
return list;
}
private String getResourcePath(Class c) {
if (c.equals(EmployeeView.class)) return "employee";
if (c.equals(WaiterBean.class)) return "waiter";
if (c.equals(TableBean.class)) return "table";
if (c.equals(ItemBean.class)) return "availableitem";
if (c.equals(OrderBean.class)) return "order";
return "";
}
...
}
The fields, getters and setters of WaiterBean and WaiterEntity, as well as OrderBean and OrderEntity, are the same. The only difference is that the 'beans' don't have JPA annotations.
edit 3: (#DonovanMuller) The server is a resource class which methods represent HTTP methods (GET, POST, PUT, DELETE) and exchange information with JSON. The methods of the server have resource annotations, such as:
#GET #Path("order/findbywaiter/{id}")
#Produces("application/json")
public List<OrderEntity> findOrdersByWaiter(#QueryParam("id") long id) { ... }
edit 4: (#DonovanMuller) This is the main part of the web resource class that is responsible for persistence:
#Path("iwaiter")
#Stateless
public class IWaiterResource {
#PersistenceContext(unitName = "ZZZ_WebServicePU")
private EntityManager em;
#Context
private UriInfo context;
#POST #Path(PATH_WAITER)
#Consumes({"application/json", "application/xml"})
public void create(WaiterEntity e) { em.persist(e); }
#POST #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void create(OrderEntity e) {
WaiterEntity waiter = e.getWaiter();
em.persist(e);
if (waiter != null) {
waiter.getOrders().add(e);
}
}
#PUT #Path(PATH_WAITER)
#Consumes({"application/json", "application/xml"})
public void update(WaiterEntity e) { em.merge(e); }
#PUT #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void update(OrderEntity e) { em.merge(e); }
#DELETE #Path(PATH_WAITER)
#Consumes({"application/json", "application/xml"})
public void deleteWaiter(#QueryParam("id") long id) { em.remove(em.find(WaiterEntity.class, id)); }
#DELETE #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void deleteOrder(#QueryParam("id") long id) { em.remove(em.find(OrderEntity.class, id)); }
private <T> List<T> findAll(Class<T> type) {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(type));
return em.createQuery(cq).getResultList();
}
#GET #Path(PATH_WAITER)
#Produces({"application/json", "application/xml"})
public List<WaiterEntity> findAllWaiters() { return findAll(WaiterEntity.class); }
#GET #Path(PATH_ORDER)
#Produces({"application/json", "application/xml"})
public List<OrderEntity> findAllOrders() { return findAll(OrderEntity.class); }
#GET #Path(PATH_WAITER + "/" + PATH_FIND_BY_ID + "/{id}")
#Produces("application/json")
public WaiterEntity findWaiter(#PathParam("id") long id) { return em.find(WaiterEntity.class, id); }
#GET #Path(PATH_ORDER + "/" + PATH_FIND_BY_ID + "/{id}")
#Produces("application/json")
public OrderEntity findOrder(#PathParam("id") long id) { return em.find(OrderEntity.class, id); }
private <T> List<T> findByName(Class<T> type, String column, String searchTag) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(type);
Root<T> root = cq.from(type);
cq.where(cb.equal(root.get(column), searchTag));
return em.createQuery(cq).getResultList();
}
#GET #Path(PATH_WAITER + "/" + PATH_FIND_BY_NAME + "/{name}")
#Produces("application/json")
public List<WaiterEntity> findWaitersByName(#QueryParam("name") String name) { return findByName(WaiterEntity.class, "name", name); }
#GET #Path(PATH_ORDER + "/" + PATH_FIND_BY_NAME + "/{name}")
#Produces("application/json")
public List<OrderEntity> findOrdersByName(#QueryParam("name") String name) { return findByName(OrderEntity.class, "orderNumber", name); }
#GET #Path("order/findbywaiter/{id}")
#Produces("application/json")
public List<OrderEntity> findOrdersByWaiter(#QueryParam("id") long id) {
WaiterEntity waiter = em.find(WaiterEntity.class, id);
return waiter.getOrders();
}
}

Your association is not mapped correctly. A bidirectional always has an owner side and an inverse side. In a OneToMany association, the inverse side must be the one side.
The inverse side does not specify how the association is mapped. It simply says: go look at the other side of the association to see how this association is mapped. This is done using the mappedBy attribute:
In Waiter:
#OneToMany(mappedBy = "waiter", cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.EAGER)
private List<OrderEntity> orders = new ArrayList<>();
In Order:
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "waiter_id")
private WaiterEntity waiter;
The way you have done it, JPA considers waiter.orders and order.waiter as two independent associations, which, unfortunately, are mapped using the same join column. The two associations thus conflict with each other.

I moved this to an answer, as the comments were getting a bit long winded.
I haven't tested this but in your create(OrderEntity e) resource method (edit 4) your waiter reference is surely detached?
#POST #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void create(OrderEntity e) {
WaiterEntity waiter = e.getWaiter(); // <-- getting a reference to a detached entity. I.e. not managed by the entity manager
em.persist(e);
if (waiter != null) {
waiter.getOrders().add(e);
}
}
If you change it to the following, does it solve your problem?
#POST #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void create(OrderEntity e) {
em.persist(e);
Waiter waiter = e.getWaiter(); // <-- The reference to the persisted OrderEntity is now managed
if (waiter != null) {
waiter.getOrders().add(e);
}
}

Related

one to one set up does allows multiple records in parent table to be related to one record other related table

Please be so kind to help me understand why, by running attached code, I have multiple records been written in parent table from my data base (MySQL) with corresponding to a record in related table, although the set up in Java code is for one to one relation (i.e. one records in parent corresponding to only one record in other related table.
I am at your disposal for any questions you might have on the subject.
many thank for support
petrisor
public class Main {
public static void main(String[] args) {
createParkingLot();
AddEmployees(1);
AddEmployees(2);
}
public static void createParkingLot(){
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("java2curs4e1PU");
EntityManager em = emf.createEntityManager();
ParkingLot p1= new ParkingLot();
p1.setParking_lot_no(1);
try{
em.getTransaction().begin();
em.persist(p1);
em.getTransaction().commit();
} finally {
em.close();
emf.close();
}
}
public static void AddEmployees(int employee_number){
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("java2curs4e1PU");
EntityManager em = emf.createEntityManager();
ParkingLot p2 = em.find(ParkingLot.class,1);
Employee a1 = new Employee();
a1.setEmployee_name("Employee_name_#"+employee_number);
a1.setParking_lot(p2);
try{
em.getTransaction().begin();
em.persist(a1);
em.getTransaction().commit();
} finally {
em.close();
emf.close();
}
}
}
+++++++++++++++++++++++++++++
related entities description:
+++++++++++++++++++++++++++++
Entity Employee
+++++++++++++++++++++++++++++
#Entity
#Table(name = "employees")
public class Employee implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String employee_name;
#OneToOne(cascade = CascadeType.ALL,optional = false,fetch =
FetchType.LAZY)
#JoinColumn(name = "id_parking_lot")
private ParkingLot parking_lot;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmployee_name() {
return employee_name;
}
public void setEmployee_name(String employee_name) {
this.employee_name = employee_name;
}
public ParkingLot getParking_lot() {
return parking_lot;
}
public void setParking_lot(ParkingLot parking_lot) {
this.parking_lot = parking_lot;
}
#Override
public String toString() {
return "Employee{" + "id=" + id + ", name=" + employee_name + ",
parking lot=" + parking_lot + '}';
}
}
++++++++++++++++++++++++++++
Entity ParkingLot:
++++++++++++++++++++++++++++
#Entity
#Table(name = "parking_lots")
public class ParkingLot implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
private int id;
private int parking_lot_no;
#OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional =
false,mappedBy = "parking_lot")
private Employee employee;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getParking_lot_no() {
return parking_lot_no;
}
public void setParking_lot_no(int parking_lot_no) {
this.parking_lot_no = parking_lot_no;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
#Override
public String toString() {
return "ParkingLot{" + "id=" + id + ", parking lot number=" +
parking_lot_no + '}';
}
}
Normally I would expect the program to through an exception as I tried to insert another Employee (Employee_name_#2) with the same parking lot (id 1).
Instead in table employees I found that I have 2 employees with same parking lot.

Exception when selecting specific columns using Hibernate and Spring Data JPA

I have a table that has a bytea column (named 'pdf') and I don't want to always select it, specially when I'm returning a list from the database, due to performance issues.
I use native queries with spring data inside the repository to solve these types of situations before (when I used eclipselink), but with Hibernate, if I don't write all the columns in the query, it throws an exception.
For test purposes, I'm trying to select only the id from the User and I still get the exception.
Example: "SELET user.id FROM user WHERE user.id = '1'"
It throws an exception saying that it did not find name in the ResultSet, if I put name in the SQL, it then says age was not found and so on, until I have to write all the columns in the SQL.
Thanks in advance for any help.
What I have tried already:
Updating/Downgrading Hibernate and Spring Data with no luck.
Creating a new entity with only the columns I need, works, but it's a messy solution for me.
Maybe the problem is the combination of the frameworks I use and the way I use them, if someone wants, I could try to upload my whole project structure.
My code:
Entity
#Entity
#Table(name = "user", schema = "portal")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "pdf")
private byte[] pdf;
#Column(name = "name")
private String name;
#Column(name = "age")
private Integer age;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public byte[] getPdf() {
return pdf;
}
public void setPdf(byte[] pdf) {
this.pdf = pdf;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Anexo)) {
return false;
}
Anexo other = (Anexo) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "br.gov.to.secad.portal.domain.User[ id=" + id + " ]";
}
}
Service
#Service
#Transactional(readOnly = true)
public class UserService implements Serializable {
private static final long serialVersionUID = 1L;
#Autowired
private IUserRepository userRepository;
public UserService() {
}
public User findOne() {
return userRepository.findOneSQL();
}
}
Repository
public interface IUserRepository extends JpaRepository<User, Serializable>, JpaSpecificationExecutor {
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
public User findOneSQL();
}
The exception:
org.postgresql.util.PSQLException: The column name name was not found in this ResultSet.
Solution
The solution is using an array of Object when I want to select anything less than what I've mapped on my Entity class, thats the limitation of Hibernate that I now understand.
So basically, the method will return Object[] and then I can iterate each position and instantiate a new entity of User with these values.
Example:
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
public Object[] findOneSQL();
I have faced the same problem, I know it is late but well there is a solution that I found elegant.
By the Spring documentation you can declare an interface and from here take the fields you want, in my case it has been something similar to this.
The interface to minimize the fields:
public interface CountryMinify {
String getName();
String getNameTranslation();
}
And my JpaRepository
public interface PlanetRepository extends JpaRepository<Planet, Long> {
#Query(value = "select p.name_country as name, p.name_country_translation as nameTranslation from vm_planet p where gid = ?1", nativeQuery = true)
CountryMinify findByCode(String codeCountry);
}
Keep in mind that the columns should be called the same as gos getter. For example: column name_country -> AS name and the getter of the interface is getName()
Try this
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
Integer findOneSQL();
Call the method like so
Integer user = userRepository.findOneSQL();
Edit 1 :
Since you are using native query you wont be able to use Projections which is a great way of accessing only certain entity fields. There is a JIRA ticket which is still under investigation.
Solution
Return List from your repository like so
#Query(value = "SELECT user.id, user.name FROM user WHERE user.id = '1'", nativeQuery = true)
List<Object[]> findOneSQL();
Iterate over the list of Objects and get your specific columns.
List<Object[]> userNative = userRepository.findOneSQL();
for (Object[] obj : userNative) {
System.out.println("User id : " + obj[0]);
System.out.println("User Name : " + obj[1]);
}

need Spring Data JPA resource entry to make one many rest call

Using Spring Data jpa and Spring Data Rest I could able to get basic CRUD operations to work. But I am facing problem with one to many (owner -> car(s)) relationship. Can any one help me in this.
Owner.java
#Entity
#Table(name = "OWNER")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Owner implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "age")
private Integer age;
#OneToMany(mappedBy = "owner")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Car> cars = new HashSet<>();
}
OwnerResource.java
#RestController
#RequestMapping("/api")
public class OwnerResource {
private final Logger log = LoggerFactory.getLogger(OwnerResource.class);
#Inject
private OwnerRepository ownerRepository;
#RequestMapping(value = "/owners",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> create(#RequestBody Owner owner) throws URISyntaxException {
log.debug("REST request to save Owner : {}", owner);
if (owner.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new owner cannot already have an ID").body(null);
}
Owner result = ownerRepository.save(owner);
return ResponseEntity.created(new URI("/api/owners/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert("owner", result.getId().toString()))
.body(result);
}
#RequestMapping(value = "/owners",
method = RequestMethod.PUT,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> update(#RequestBody Owner owner) throws URISyntaxException {
log.debug("REST request to update Owner : {}", owner);
if (owner.getId() == null) {
return create(owner);
}
Owner result = ownerRepository.save(owner);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert("owner", owner.getId().toString()))
.body(result);
}
#RequestMapping(value = "/owners",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<List<Owner>> getAll(#RequestParam(value = "page" , required = false) Integer offset,
#RequestParam(value = "per_page", required = false) Integer limit)
throws URISyntaxException {
Page<Owner> page = ownerRepository.findAll(PaginationUtil.generatePageRequest(offset, limit));
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/owners", offset, limit);
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
#RequestMapping(value = "/owners/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> get(#PathVariable Long id) {
log.debug("REST request to get Owner : {}", id);
return Optional.ofNullable(ownerRepository.findOne(id))
.map(owner -> new ResponseEntity<>(
owner,
HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
}
OwnerRepository.java
/**
* Spring Data JPA repository for the Owner entity.
*/
public interface OwnerRepository extends JpaRepository<Owner,Long> {
}
The basic crud operation is working fine for Owner. But now I need to get all cars of a particular owner for that I need to add one rest call entry in OwnerResource.java and a method entry in OwneRepository.java. I tried different ways but getting many errors and is not working. The following is what I tried.
In OwnerRepository.java
Owner findAllByOwnerId(Long id);//But eclipse shows error here for this method
In OwnerResource.java
//Get All Cars
#RequestMapping(value = "/{id}/cars",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> getAll(#PathVariable Long id) {
log.debug("REST request to get All Cars of the Owner : {}", id);
return Optional.ofNullable(ownerRepository.findAllByOwnerId(id))
.map(owner -> new ResponseEntity<>(
owner,
HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
But these two changes are not working out. I am beginner to spring data jpa and spring data rest. Can any one help me in correcting these two so that I can get all cars of the owner.
I believe it shows an error because the findAll returns a different type of object: List, Page, etc...
Try this:
List<Owner> findAllByOwnerId(#Param("id") Long id);
That will return you a list of objects. If you want to return with pagination, than you need this instead:
Page<Owner> findAllByOwnerId(#Param("id") Long id, Pageable pageable);
I hope this helps, let me know how it works for you.

JPA One-to-Many relationship using a List - OrderBy ignored/not working

I'll try to formulate the question more simple:
#Entity
public class One implements Serializable {
...
#Id
#GeneratedValue
private Long id;
#OneToMany
#OrderBy("name ASC")
private List<Many> many;
...
First I populate the List with some Many-Entities and persist the One-Entity. Second I retrieve (em.find) the One-Entity expecting the List in ascending order by Many#name, but it's not ordered by name. The List is ordered by id. Complete code see below if necessary.
Original post some days ago:
I'm using a current Netbeans Glassfish bundle.
Product Version: NetBeans IDE 8.0 (Build 201403101706)
Updates: NetBeans IDE is updated to version NetBeans 8.0 Patch 2
Java: 1.7.0_51; Java HotSpot(TM) 64-Bit Server VM 24.51-b03
Runtime: Java(TM) SE Runtime Environment 1.7.0_51-b13
System: Mac OS X version 10.9.3 running on x86_64; UTF-8; de_DE (nb)
The JPA #OrderBy annotation is completely ignored.
#Entity
public class One implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
#OneToMany
#OrderBy("name ASC")
private List<Many> many;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Many> getMany() {
return many;
}
public void setMany(List<Many> many) {
this.many = many;
}
}
The many Entity
#Entity
public class Many implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
private String name;
public Many() {
}
public Many(String name) {
this.name = 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;
}
}
The service class (EJB)
#Stateless
public class Service {
#PersistenceContext(unitName = "cwPU")
private EntityManager em;
public One createOne() {
return em.merge(new One());
}
public Many createMany(String name) {
return em.merge(new Many(name));
}
public One add(Long oneId, Long manyId) {
One one = em.find(One.class, oneId);
Many many = em.find(Many.class, manyId);
one.getMany().add(many);
return one;
}
public One find(Long id) {
One one = em.find(One.class, id);
return one;
}
}
The main class
public class Main {
public static void main(String[] args) throws NamingException {
EJBContainer container = EJBContainer.createEJBContainer();
Context ctx = container.getContext();
Service service = (Service) ctx.lookup("java:global/classes/Service");
One one = service.createOne();
Many many = service.createMany("the-first");
service.add(one.getId(), many.getId());
many = service.createMany("a-second");
one = service.add(one.getId(), many.getId());
one = service.find(one.getId());
System.out.println("-------------------------------------------------");
for (Many m : one.getMany()) {
System.out.println(m.getName());
}
container.close();
}
}
The output:
the-first
a-second
No matter what I write to the #OrderBy annotation (name ASC, name DESC, id ASC, id DESC), the output is always the same ascending order by the id.
Any idea what I'm missing?
The #Orderby annotation doesn't actually work that way. According to the javadoc, the annotation "Specifies the ordering of the elements of a collection ...at the point when the collection is retrieved."
So the annotation affects the result of the query (find), but does not dictate the order in the collection you store the result set into.
The solution is calling em.refresh (at the right place) as stated from Chris and WPrecht. I had to do this in a separate EJB method.
This did not work:
public One find(Long id) {
em.refresh(em.find(One.class, id)); // did not work
One one = em.find(One.class, id);
return one;
}
Adding a separate refresh method
public void refresh(Long id) {
em.refresh(em.find(One.class, id));
}
and calling it in the main program
...
service.refresh(one.getId());
one = service.find(one.getId());
...
works!
Probably I have to do more reading to understand caching.

Object: entity.ENTITY[ id=null ] is not a known entity type

this is a similar post to one I have seen before regarding this exception but I am utterly lost. I have yet to persist an entity to a database using JPA, although I have read from tables using it no problem. My setup is Netbeans 7.1 using Glassfish 3.1.1, EclipseLink is my persistence provider. I have a very simple scenario where I just want to test writing a persons name and age into the database and having the id auto increment. Its an MySql database with the fields: Id, FirstName and Age. Heres my code:
Web servlet to take in name and age from html form:
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userPath = request.getServletPath();
if(userPath.equals("/addUser")){
//get request parameters from form
String name = request.getParameter("name");
String age = request.getParameter("age");
//set request attributes to be used by forwarded page
request.setAttribute("name", name);
request.setAttribute("age", age);
//create manager class to add person to database
Manager manager = new Manager();
manager.addPerson(name, age);
userPath = "/result";
}
// use RequestDispatcher to forward request internally
String url = "/WEB-INF/view" + userPath + ".jsp";
try {
request.getRequestDispatcher(url).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Manager class that takes in name and age, creates a person object and persists it.
public class Manager {
private static final String PERSISTENCE_UNIT_NAME = "FormPU";
private static EntityManagerFactory factory;
public Manager() {
}
public void addPerson(String name, String age) {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
Persons persons = new Persons();
persons.setName(name);
persons.setAge(age);
em.getTransaction().begin();
em.persist(persons);
em.getTransaction().commit();
em.close();
}
}
Persons entity class:
/**
*
* #author esmiala
*/
#Entity
#Table(name = "persons")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Persons.findAll", query = "SELECT p FROM Persons p"),
#NamedQuery(name = "Persons.findById", query = "SELECT p FROM Persons p WHERE
p.id = :id"),
#NamedQuery(name = "Persons.findByFirstName", query = "SELECT p FROM Persons p
WHERE p.firstName = :firstName"),
#NamedQuery(name = "Persons.findByAge", query = "SELECT p FROM Persons p WHERE
p.age = :age")})
public class Persons implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(name = "Id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "FirstName")
private String firstName;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "Age")
private String age;
public Persons() {
}
public Persons(Integer id) {
this.id = id;
}
public Persons(Integer id, String firstName, String age) {
this.id = id;
this.firstName = firstName;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Persons)) {
return false;
}
Persons other = (Persons) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "entity.Persons[ id=" + id + " ]";
}
}
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com
/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="FormPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/form</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
Note: I have also tried setting exclude-unlisted-classes tag to true and list the class seperately but that didn't work either.
The exception:
WARNING: StandardWrapperValve[Controller]: PWC1406: Servlet.service() for servlet
Controller threw exception
java.lang.IllegalArgumentException: Object: entity.persons[ id=null ] is not a
known entity type.
atorg.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObject
ForPersist(UnitOfWorkImpl.java:4141)
atorg.eclipse.persistence.internal.jpa.EntityManagerImpl.
persist(EntityManagerImpl.java:368)
at manager.Manager.addPerson(Manager.java:36)
at controller.Controller.doPost(Controller.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
...and so on. Any help would be greatly appreciated!
<exclude-unlisted-classes> doesn't work as you would expect - the very presence of this element in persistence.xml disables automatic discovery of #Entity classes, no matter what's inside it.
Also, #Entity(name="persons") is probably not what you want, use #Entity #Table (name="persons") instead.
So you say you can read the class fine, but get an error persisting a new instance?
Can you update an object that you read?
It seems you are having some kind of class loader issue. Somehow you have the class on your classpath twice, or have two different class loaders. The object you are passing to persist is from a different class loader than the one JPA is using. You can check the class loader of what was read, and of the object being persisted to see how they differ.
Have you redeployed you app, or hotdeployed? Does it work if you shut down/restart the server properly. Ensure you are closing your old EntityManagerFactory before redeploying.
Concerning youe concrete problem, try to see if this link helps.
Anyway, the way you are instantiating the EntityManager is not thread safe.
You can see here why. Or, better, you can use NetBeans' wizard for creating JPA controller classes from entity classes, and see how it injects the EntityManager:
#PersistenceContext
private EntityManager em;
See also that the controller classes (the equivalent of your Manager POJO) have the Stateless annotation. This is because you can safely inject an EJB (in this case the EntityManager) only in an object whose lifecycle is managed by the web container (see here for further reference about Accessing Enterprise Beans).