Jpa-One To Many and Restws - rest

I have two classes, Customer and CustomerProduct. I want the customerId(from customer) to be mapped in CustomerProduct. I used OneToMany mapping as follows.
Customer.java
#XmlTransient
#OneToMany(fetch = FetchType.EAGER, mappedBy = "customer")
public Set<CustomerProducts> getCustomerProducts() {
return customerProducts;
}
CustomerProduct.java
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "customer_id", nullable = false)
public Customer getCustomer() {
return customer;
}
I was able to save the datas, but for selecting a customer, I used named query which returned a Customer with CustomerProduct as well. I used restws. I used Response.ok(cust).build(); where cust had all the values in the server side.
When I get the response in the client side, I am getting the customers but not the CustomerProduct.
Did I miss something?

You need to remove the #XmlTransient annotation, it prevents the customerProducts property from serialization to a response.
See: http://docs.oracle.com/javaee/6/api/javax/xml/bind/annotation/XmlTransient.html
And to avoid infinity loop during serialization you either need add #XmlTransient to the customer property of the CustomerProduct entity or fetch this property lazily.

Related

JPA Criteria API join on 3 tables and some null elements

I have one parent entity that has two child entities as attributes.
I want to select all elements from the parent entity that have EITHER a childOne with a given parameter as personal attribute OR childTwo with that same given parameter as personal attribute.
Here are my three classes simplified:
The Parent Object:
#Entity
public class ParentObject {
#Id
private int id;
private int fkChildOne;
private int fkChildTwo;
#ManyToOne
#JoinColumn(name = "fk_child_one_id", referencedColumnName =
"child_one_id")
private ChildOne childOne;
#ManyToOne
#JoinColumn(name = "fk_child_one_id", referencedColumnName =
"child_one_id")
private ChildTwo childTwo;
// getters and setters
}
The Child One Object:
#Entity
public class ChildOne {
#Id
private int childOneId;
private String nameChildOne;
#OneToMany
#JoinColumn(name = "fk_child_one_id")
private List<ParentObject> parents;
// getters and setters
}
The Child Two Object:
#Entity
public class ChildTwo {
#Id
private int childOneId;
private String nameChildTwo;
#OneToMany
#JoinColumn(name = "fk_child_two_id")
private List<ParentObject> parents;
// getters and setters
}
The Specs Class:
public static Specification<ParentObject> checkName(String name) {
return Specifications.where(
(root, query, builder) -> {
final Join<ParentObject, ChildOne> joinchildOne =
root.join("childOne");
final Join<ParentObject, ChildTwo > joinchildTwo =
root.join("childTwo");
return builder.or(
builder.equal(joinchildOne .get("nameChildOne"), name),
builder.equal(joinchildTwo .get("nameChildTwo"), name)
);
}
);
}
When this spec is called in my service, I get no results. However, if I comment out one of the two joins and the corresponding Predicate in my builder.or method, then I get some results but they obviously don't match what I'm looking for, which is to select every ParentObject that have either ChildOne with that parameter or ChildTwo with that paramater.
Any clue what's wrong with the code ?
Finally got the solution : to fetch all the corresponding results, I had to add the type of the join which would be left join, since I wanted to fetch all ParentObjects regardless of owning childOne or ChildTwo objects.
final Join<ParentObject, ChildOne> joinchildOne =
root.join("childOne", JoinType.LEFT);
final Join<ParentObject, ChildTwo > joinchildTwo =
root.join("childTwo", JoinType.LEFT);
Great, now you have to choose if you need to join or fetch.To optimize the query and the memory, you should establish the relations as Lazy (#ManyToMany (fetch = FetchType.LAZY)), so you will only bring the objects that you demand.
The main difference is that Join defines the crossing of tables in a variable and allows you to use it, to extract certain fields in the select clause, for example, on the other hand, fetch makes it feed all the objects of that property. On your example,
a select from parent with join of children (once the relation is set to lazy) would only bring initialized objects of type parent, however if you perform a fetch, it would bring the parent and child objects initialized.
Another modification I would make is to change the type of the identifier to non-primitive, so that it accepts null values, necessary for insertion using sequences

Feed a list with the last value

I have theses entity and I do this query.
select r from RentAmount r Join r.lodger l join l.bailList b where r.unpaidBalance > 0 and (r.paymentDueDate > :date or r.paymentDueDate is null ) and b.paymentPeriod= order by r.rentAmountId")
Is there a way to feed Lodger.bailList only with the last bail or i would need to loop on every record to get this information?
#Entity
public class RentAmount {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long rentAmountId;
#OneToOne
private Lodger lodger;
}
#Entity
public class Lodger{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long lodgerId;
#OneToOne(fetch = FetchType.LAZY, mappedBy="lodger")
private RentAmount rentAmount;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY, mappedBy = "lodger", orphanRemoval = true)
private List<Bail> bailList;
}
#Entity
public class Bail {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long bailId;
#Enumerated(EnumType.STRING)
private PaymentPeriodEnum paymentPeriod;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lodger_id")
private Lodger lodger;
}
There are a few options:
One (Non JPA, Hibernate Only)
Ensure the collection is correctly ordered and mark it is as extra lazy. You will have access to the whole collection but accessing of individual items will not trigger a full load.
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html
"Extra-lazy" collection fetching: individual elements of the
collection are accessed from the database as needed. Hibernate tries
not to fetch the whole collection into memory unless absolutely
needed. It is suitable for large collections.
The mapping will look like:
#OneToMany(mappedBy = "lodger")
#LazyCollection(LazyCollectionOption.EXTRA)
#OrderBy("theRelevantProperty ASC")
private List<Bail> bailList;
public void getCurrentBail(){
//will only load this item from the database
return bailList.get(bailList.size() - 1);
}
Two (Non JPA, Hibernate Only.)
Use the #Where annotation to filter the collection so that while still #OneToMany, only one element will be accessible.
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-collection
The mapping will look like:
#OneToMany(mappedBy = "lodger")
#Where(clause="some native sql which will filter to include onyl 1item"))
private List<Bail> bailList;
public void getCurrentBail(){
//will be the only item accessible
return bailList.get(0);
}
Three (JPA Compliant)
Would involve creating views at the database level. Various options in this area. If we are only ever interested in the current bail then this view would be similar to option 2 above. Simply point the Bail entity to this view rather than the concrete table:
#Entity
#Table(name = "vw_active_bail")
public class Bail {
}

Jpa eclipselink bug when try persist collection by another entity

Hello i have got one entity which contains collection of object:
#Entity
public class ResourceType{
#Id
public Integer id;
#ManyToMany(mappedBy = "resourcesTypes")
private Set<Resource> resources = new HashSet<>();
}
As you see this entity contains collection of Resource
#Entity
public class Resource{
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "RESOURCE_TYPE_CROSS", joinColumns = { #JoinColumn(name = "RESOURCE_ID") }, inverseJoinColumns = { #JoinColumn(name = "RESOURCE_TYPE_ID", referencedColumnName = "ID") })
private List<ResourceType> resourcesTypes = new ArrayList<>();
}
So i guess if i get all resourceTypes with all resources this collection is in local cache.
But if i try persist resource :
#Override
public ResourcesDTO createResource(ResourcesDTO resource) throws CreateResourceException {
if (resource.getResourcesTypes().isEmpty()) {
throw new CreateResourceException("Can not create resouce " + resource.getName()
+ " none resource types is set");
resourceDAO.create(map(resource));
log.debug("Created resource: " + r);
resource.setId(r.getId());
return resource
}
If i perssist Resource with ResourcesTypes and next i will get all ResourceTypes entity manager do not found new Resources. But in my cross table resource_type_cross everything is ok. i will try to do something like that after create new resource:
for(ResourceType rt : resource.getResourceTypes()){
em.refresh(rt);
}
But its not working properly. After i will restart server everything is fine. But why entity manager do not refresh resource type ??
This is what i use to read all ResourceTypes:
public ResourceType getAllResourceTypes(){
em.createQuery("Select n from Resource n left join fetch n.children");
return em.find(ResourceType.class, 0); //0 - ROOT
}
as follow article : http://www.tikalk.com/java/load-tree-jpa-and-hibernate
The Main question is that :
create or update entity by one side do not update another, so in my case i create and update resource type by resource entity, but i am using resouce type to get all resource.
First, there is a problem with your ManyToMany mappings. You have made both sides unidirectional accessing the same join table instead of bidirectional. One side should control the mapping, with the other set to mappedby the owning side.
Second, have you flushed or committed the changes when you refresh ResourceTypes? It is probably better to maintain both sides by setting the reference in code rather than query to refresh each and every ResourceType

JPA Query Many To One nullable relationship

I have the following entities and would like to seek help on how to query for selected attributes from both side of the relationship. Here is my model. Assume all tables are properly created in the db. JPA provider I am using is Hibernate.
#Entity
public class Book{
#Id
private long id;
#Column(nullable = false)
private String ISBNCode;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = false)
private Person<Author> author;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
private Person<Borrower> borrower;
}
#Inheritance
#DiscriminatorColumn(name = "personType")
public abstract class Person<T>{
#Id
private long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Info information;
}
#Entity
#DiscriminatorValue(PersonType.Author)
public class Author extends Person<Author> {
private long copiesSold;
}
#Entity
#DiscriminatorValue(PersonType.Borrower)
public class Borrower extends Person<Borrower> {
.....
}
#Entity
public class Info {
#Id
private long id;
#Column(nullable=false)
private String firstName;
#Column(nullable=false)
private String lastName;
......;
}
As you can see, the book table has a many to one relation to Person that is not nullable and Person that is nullable.
I have a requirement to show, the following in a tabular format -
ISBNCode - First Name - Last Name - Person Type
How can I write a JPA query that will allow me to select only attributes that I would want. I would want to get the attributes ISBN Code from Book, and then first and last names from the Info object that is related to Person Object that in turn is related to the Book object. I would not want to get all information from Info object, interested only selected information e.g first and last name in this case.
Please note that the relation between the Borrower and Book is marked with optional=true, meaning there may be a book that may not have been yet borrowed by someone (obviously it has an author).
Example to search for books by the author "Marc":
Criteria JPA Standard
CriteriaQuery<Book> criteria = builder.createQuery( Book.class );
Root<Book> personRoot = criteria.from( Book.class );
Predicate predicate = builder.conjunction();
List<Expression<Boolean>> expressions = predicate.getExpressions();
Path<Object> firtsName = personRoot.get("author").get("information").get("firstName");
expressions.add(builder.equal(firtsName, "Marc"));
criteria.where( predicate );
criteria.select(personRoot);
List<Book> books = em.createQuery( criteria ).getResultList();
Criteria JPA Hibernate
List<Book> books = (List<Book>)sess.createCriteria(Book.class).add( Restrictions.eq("author.information.firstName", "Marc") ).list();
We recommend using hibernate criterias for convenience and possibilities.
Regards,

GWT Resolver attribute of relationship can not be resolved

I'm working on a GXT project using JPA for persistence, but I'm facing an issue with bidirectionnal relationship persistence.
I have those two Entities :
#Entity
#Table(name = "ACTV_REQ", catalog = "erpdb")
#AttributeOverride(name = "id", column = #Column(name = "ID", nullable = false, columnDefinition = "BIGINT UNSIGNED"))
#NamedQueries(value = {
#NamedQuery(name = "findByPerson", query="select object(m) from ActvReq m where m.people= :people")
})
public class ActvReq extends BaseEntity {
#ManyToOne
#JoinColumn(name = "PPL_ID")
#NotNull
private People people;
#ManyToOne
#JoinColumn(name = "ACTV_TYP_ID")
private ActivityTyp actvTyp;
#ManyToOne
#JoinColumn(name= "PPL_ACTV_RIGHT_ID")
private PeopleActvRight pplActvRight;
#Column(name = "DESCR")
private String desc;
}
And :
#Entity
#Table(name = "PPL_ACTV_RIGHT", catalog = "erpdb")
#AttributeOverride(name = "id", column = #Column(name = "ID", nullable = false, columnDefinition = "BIGINT UNSIGNED"))
#PeopleActvRightBeanConstraint
#NamedQueries(value = {
#NamedQuery(name = "findByPeople", query="select object(m) from PeopleActvRight m where m.people= :people")
})
public class PeopleActvRight extends BaseEntity {
#ManyToOne
#JoinColumn(name="ACTV_TYP_ID")
#NotNull
ActivityTyp type;
#ManyToOne
#JoinColumn(name="PPL_ID")
#NotNull
People people;
#ManyToOne
#JoinColumn(name="ACTV_RIGHT_ID")
ActvRight actvRight;
#OneToMany(mappedBy="pplActvRight",cascade=CascadeType.ALL)
private List<ActvReq> actvRequests = new ArrayList<ActvReq>();
}
(I did not copy getters and setters but thoses methods exists.)
For the persistence of ActvReqProxy, it's basically done that way in my EditorPresenter :
getRequestContext().persistAndReturn(getModel()).with("actvTyp","people","pplActvRight").fire(new Receiver<M>() {
#Override
public void onSuccess(M response) {
unsetContext();
onSaveSuccess( response );
}
});
And the response pplActvRight is already null in the response I get, but in getModel() pplActvReqProxy is set.
On server side I've a service which calls the following method of my DAO :
public ActvReq persistAndReturn(ActvReq entity){
em.getTransaction().begin();
em.persist(entity);
em.close;
return entity;
}
And when I'm trying to persist a ActvReqProxy from my editor, using method with("pplActvRight","people",actvType"), I don't get any errors, but in my DB the entity is not entirely persisted. I mean a new ActvReq is created in the DB but field PPL_ACTV_RIGHT_ID remains null. (It works fine for people and actvTyp)
EDIT : In fact I assume the problem is located on GWT Resolver in resolveDomainValue, it can not resolve the attribute pplActvRight. It's as if my EntityProxy object doesn't exists on server-side.
Any ideas?
So at the beginning of persistAndReturn on server side it is already null? If so, then at least we know that it has nothing to do with JPA.
And you're sure that on client side it is set to something other than null on proxy before calling persistAndReturn? You can easily verify it: using Eclipse debugger it is possible to see JSON code to which proxy will be serialized (one of fields of proxy that you can see when you select proxy object in debugger). Please make sure that pplActvRight key is there with not-null value.
If so, maybe you should debug GWT source code that translates proxies to server-side entities to check what is being done with that pplActvRight property (why isn't it assigned to corresponding ActvReq server side instance). I can't remember what the class name doing this stuff was but if you won't be able to find it I can search it for you.