Losing id (primary key) value stored in a List from DAO to Business through an EJB - mysql

I want to display a list of users in an XHTML page. I'm sending a request from my managedBean to the Business through an EJB (3.0) then another request to the DAO still through an EJB (3.0). I'm using JPA 2 and a MySQL database with an entity manager.
I'm sending the following request to my database
#Remote(IDaoUser.class)
#Stateless
Public class DaoUser implements IDaoUser
#PersitenceContext(unitName = "persistence_unit")
Private EntityManager em;
#Override
Public List<User> getAll() {
Query query = em.createQuery("SELECT u FROM User u");
List<User> users = query.getResultList();
return users;
}
At that point everything's fine and I get all my users in my list with all attributes especially id (primary key). My user class has one attribute (birthdate) and inherits from a super class Parent (name, forename, mail, phone...) which inherits again from another class called Who which has just one attribute called id (the primary key).
Then I return my List (users) to the business through an EJB and once in the business I realise all the id attributes are 0. I kept all the others attributes (name, forename...) except ids and I can't figure out why I'm losing these values.
There are well stored in my List in the DAO but all changed to 0 once in the business.
Here is my business class which is very simple
#Remote(IBusinessUser.class)
#Stateless
Public class BusinessUser implements IBusinessUser
#EJB
private IDaoUser proxy;
#Override
Public List<User> getAll() {
List<User> users = proxy.getAll();
return users;
}

Given the description of the problem, I would ask some questions
Are the parent classes entities themselves, i.e. are they annotated with #Entity.
You need to ensure that #Id is on your primary key. Do you have the #Id annotation on the primary key.
Experience has taught me to always have the #Id attribute in class or at least in a parent class tagged with the #MappedSuperclass. And some people still have problems with retrieving their id fields from the mapped super class.
So see the JEE documentation for using the MappedSuperclass annotation. This may require changing your object inheritance model but that shouldn't be a problem given your requirement.

Thanks for your help. Actually both parent classes are themselves entities. My super class "Who" is the only one having an id attribute (primary key) with the annotation #Id. I can't tag my super class with the #MappedSuperclass since it is associated to another class.

Related

Spring Data Rest Ambiguous Association Exception

The newly added LinkCollectingAssociationHandler is throwing a MappingException due to an ambiguous association in my domain class.
The links array looks like this:
[<http://localhost:8080/rooms/2/roomGroups>;rel="roomGroups", <http://localhost:8080/rooms/2/userGroup>;rel="userGroup", <http://localhost:8080/rooms/2/room>;rel="room", <http://localhost:8080/rooms/2/originatingConferences>;rel="originatingConferences", <http://localhost:8080/rooms/2/user>;rel="user"]
And it is trying to add another 'room' relation when it throws the exception.
The issue is that it seems to be adding links to relations which I have explicitly marked with #RestResource(exported = false)
Here is an example of a relation which I believe is causing this issue:
#JsonIgnore
#RestResource(exported = false)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.room", cascade = {CascadeType.REMOVE})
private Set<RoomsByUserAccessView> usersThatCanDisplay = new HashSet<>();
The type RoomsByUserAccessView has an embedded id made up of a Room and a User.
I have also annotated the embedded id property with:
#JsonIgnore
#RestResource(exported = false)
private RoomsByUserAccessViewId pk = new RoomsByUserAccessViewId();
and its properties like this:
#JsonIgnore
#RestResource(exported = false)
private Room room;
#JsonIgnore
#RestResource(exported = false)
private User userWithAccess;
public RoomsByUserAccessViewId() {
//
}
How can I get it to ignore these relations properly when serializing to JSON?
My code was working prior to DATAREST-262 (https://github.com/spring-projects/spring-data-rest/commit/1d53e84cae3d09b09c4b5a9a4caf438701527550)
The full error message returned when I try to visit the rooms/ endpoint is as follows:
{
timestamp: "2014-03-17T13:38:05.481-0500"
error: "Internal Server Error"
status: 500
exception: "org.springframework.http.converter.HttpMessageNotWritableException"
message: "Could not write JSON: Detected multiple association links with same relation type! Disambiguate association #com.fasterxml.jackson.annotation.JsonIgnore(value=true) #javax.persistence.ManyToOne(fetch=EAGER, cascade=[], optional=true, targetEntity=void) #org.springframework.data.rest.core.annotation.RestResource(description=#org.springframework.data.rest.core.annotation.Description(value=), path=, exported=false, rel=) private com.renovo.schedulerapi.domain.Room com.renovo.schedulerapi.domain.RoomsByUserAccessViewId.room using #RestResource! (through reference chain: org.springframework.hateoas.PagedResources["content"]->java.util.UnmodifiableCollection[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Detected multiple association links with same relation type! Disambiguate association #com.fasterxml.jackson.annotation.JsonIgnore(value=true) #javax.persistence.ManyToOne(fetch=EAGER, cascade=[], optional=true, targetEntity=void) #org.springframework.data.rest.core.annotation.RestResource(description=#org.springframework.data.rest.core.annotation.Description(value=), path=, exported=false, rel=) private com.renovo.schedulerapi.domain.Room com.renovo.schedulerapi.domain.RoomsByUserAccessViewId.room using #RestResource! (through reference chain: org.springframework.hateoas.PagedResources["content"]->java.util.UnmodifiableCollection[0])"
}
I had a very similar problem . When adding a bidirectional relationship between two entities
I got an exception ""Could not write JSON: Detected multiple association links with same
relation type!" , While trying some solutions that i found here
(#JsonIgnore, #JsonIdentity, #RestResource, I also tried to do what Oliver offered
)
(The relation was properly defined with #JsonManagedReference and #JsonBackReference)
Nothing helped.
At the end i managed to understand that spring data rest is trying to
figure out if the related entity is linkable ( while trying to build the json of the
requested entity )
(LinkCollectingAssociationHandler : doWithAssociation -> isLinkableAssociation)
, For doing that he is looking for a repository that deals with the
related entity. After adding a repository for the related entity.. works like a charm..
(I suppose that after adding a repo a mapping RepositoryAwareResourceInformation is being
created for this entity (that is what I saw at debug).
I had this issue, and solved it as Ron suggests, but I thought I would expound a little. I didn't fully understand the first couple times I read Ron's answer...
#NodeEntity
public class Player extends Entity
#NodeEntity
public class PlayerTrade extends Entity
#NodeEntity
public class Trade extends Entity
I had repositories for Player and Trade, but none for PlayerTrade:
#RepositoryRestResource
public interface PlayerRepository extends GraphRepository<Player> {
#RepositoryRestResource
public interface TradeRepository extends GraphRepository<Trade> {
As soon as I added the last repo it worked.
#RepositoryRestResource
public interface PlayerTradeRepository extends GraphRepository<PlayerTrade>
I tried using #RestResource with rel or excluded, but couldn't get it dialed in. Does this mean that every entity in our JSON graph must have a repository?

"org.hibernate.ObjectNotFoundException: No row with the given identifier exists" but it does exists

I'm using hibernate for my web service.
I'm able to list all the records, but unable to get just one.
The table contains:
ID (VARCHAR) VALUE(BIT)
celiac 1
rate 1
suggestions 0
The error shown is:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.pfc.restaurante.models.Device#id="xxxxxx"]
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
And the main code:
#JsonAutoDetect
#Entity
#Table(name = "SETTINGS")
public class Settings implements Serializable{
#Id
#Column(name="ID")
private String id;
#Column(name="VALUE", nullable=false)
private boolean value;
(...)
}
//////////////////7
#Controller
#RequestMapping("/settingsService")
public class SettingsServiceController {
#Autowired
SettingsService settingsService;
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public #ResponseBody Settings find(#PathVariable("id") String id){
return settingsService.find(id);
}
(...)
}
I've read around that it could be because DB incongruence with my entity (some nullable = true when it shouldn't), but I've checked it already and there is no such a thing.
Could someone lend me a hand?
Thanks in advance!
Your error refers to an entity named 'Device' but your code shows an entity 'Settings'. Are they the same?
I've seen this error only in 2 situations:
The main entity does not exist in the DB and Session.load() is used. Use Session.get() and check for null instead.
Broken relationships. Consider this: EntityA owns a relation to EntityB. EntityB is deleted while the FK in EntityA is left untouched. So, whenever HB tries to load the link A-B the error happens. This can happen when running a normal search or even when saving/refreshing EntityA (HB needs to refresh the link as well).

Persisting a Many-to-Many entity by adding to a List of entities

I am getting a list of entities and attempting to add more values to it and have them persist to the data base... I am running into some issues doing this... Here is what I have so far...
Provider prov = emf.find(Provider.class, new Long(ID));
This entity has a many to many relationship that I am trying to add to
List<Organization> orgList = new ArrayList<Organization>();
...
orgList = prov.getOrganizationList();
So I now have the list of entities associated with that entity.
I search for some entities to add and I place them in the orgList...
List<Organization> updatedListofOrgss = emf.createNamedQuery("getOrganizationByOrganizationIds").setParameter("organizationIds", AddThese).getResultList();
List<Organization> deleteListOfOrgs = emf.createNamedQuery("getOrganizationByOrganizationIds").setParameter("organizationIds", DeleteThese).getResultList();
orgList.addAll(updatedListofOrgss);
orgList.removeAll(deleteListOfOrgs);
As you can see I also have a list of delete nodes to remove.
I heard somewhere that you don't need to call persist on such an opperation and that JPA will persist automatically. Well, it doesn't seem to work that way. Can you persist this way, or will I have to go throught the link table entity, and add these values that way?
public class Provider implements Serializable {
#Id
#Column(name="RESOURCE_ID")
private long resourceId;
...
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="DIST_LIST_PERMISSION",
joinColumns=#JoinColumn(name="RESOURCE_ID"),
inverseJoinColumns=#JoinColumn(name="ORGANIZATION_ID"))
private List<Organization> organizationList;
...//getters and setters.
}
The link table that links together organizations and providers...
public class DistListPermission implements Serializable {
#Id
#Column(name="DIST_LIST_PERMISSION_ID")
private long distListPermissionId;
#Column(name="ORGANIZATION_ID")
private BigDecimal organizationId;
#Column(name="RESOURCE_ID")
private Long resourceId;
}
The problem is that you are missing a cascade specification on your #ManyToMany annotation. The default cascade type for #ManyToMany is no cascade types, so any changes to the collection are not persisted. You will also need to add an #ElementDependent annotation to ensure that any objects removed from the collection will be deleted from the database. So, you can change your Provider implementation as follows:
#ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#ElementDependent
#JoinTable(name="DIST_LIST_PERMISSION",
joinColumns=#JoinColumn(name="RESOURCE_ID"),
inverseJoinColumns=#JoinColumn(name="ORGANIZATION_ID"))
private List<Organization> organizationList;
Since your Provider class is managed, you should not need to merge the entity; the changes should take effect automatically when the transaction is committed.

Hibernate Annotations & Inheritance

I have multiple tables in a MySQL database. Lets say they look like this:
Book:
title, subject, publisher, book_author
Journal:
title, subject, publisher, journal_name
Blog:
title, subject, website, blog_author
ENews:
title, subject, website, news_paper_name
The particular structure is irrelevant to the problem. In reality, there are around 20 columns that all of the tables share and more that are unique to a few or just one table. The point is, they all share some columns. I want to use Hibernate to access these, using annotated classes. I don't want to have 5+ classes that each have 20+ redundant fields, each with an accessor and mutator. I would like a class structure something like this:
abstract Publication { title, subject }
abstract PrintPublication { publisher }
Book { book_author }
Journal { journal_name }
abstract Online Publicaiton { website }
Blog { blog_author }
ENews { news_paper_name }
However, I can't for the life of me figure out how to get this to work. Each of the concrete classes is a single table in the database. I thought the solution would be a table per class (#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)), but that threw a number of interesting errors.
What is the proper solution to all of this? Besides altering the table structure. The database is not mine and I have not been given rights to change it.
If there is no need for type inheritance between entities, for that purpose there is MappedSuperClass. Idea is that you define all the common persistent attributes and their mappings in mapped superclass and entities will extends it.
Result is that mappings will apply to entity that extends mapped superclass, but from the point-of-view of persistence there is not is-a relationship between entity and mapped superclass.
Following provides starting point:
#MappedSuperclass
public class Publication {
String title;
#Column (name="subject_of_publication")
String subject;
...
}
#MappedSuperclass
public class PrintPublication extends Publication {
String publisher;
...
}
#Entity
public class Book extends PrintPublication {//inherits persistent attributes
...
String author;
}
You can also have mapped superclasses in other levels in entity hierarchy and override mappings in entities as needed.
But if you have to in some point threat for example Book and Blog as one type, then mapped superclass is not way to go, because you cannot query it.

DOM4J createQuery not eagerly fetching

I have an entity which contains a OneToMany relationship, with eager fetching, with a second entity. This second entity has two OneToOne relationships, with eager fetching also, to a third and fourth class. The OneToOne relationships are unidirectional.
I am calling createQuery() from a DOM4J session sending in "from entity" as the HQL. In the return I get the second entity but it contains only the IDs of the third and fourth entities instead of the complete contents. To me it looks like those third and fourth entities are not being eagerly fetched. I can't reproduce the code exactly but here is the most relevant parts.
#Entity
public class Event extends EventParent {
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinColumn(name="eventId")
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Pair> pairs=new HashSet<MarPair>();
}
#Entity
public class Pair extends PairParent {
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Info info;
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Results results;
}
#Entity
public class Info {
private String name;
private Date time;
}
#Entity
public class Results {
private String name;
private Date time;
}
Finally here is the code I am using for the query:
public void retrieve() {
String hqlQry = "from Event";
Session session = dom4JSessionFactory.getCurrentSession();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
List results = dom4jSession.createQUery(hqlQuery).list();
}
As I mentioned, from this query I am getting back an integer for the value of info and results which is the key to the info and results table instead of the actual data being retrieved from the info and results table.
Relevant Information:
Spring 2.5.4
Hibernate 3.2.6
Hibernate Annotations 3.3.1.GA
dom4JSessionFactory is of type org.springframework.orm.hibernate3.LocalSessionFactoryBean
The entity "Event" is actually the 7th class down in a class hierarchy (don't know if this matters or not)
I did leave out a lot of information hoping that it was not necessary. If there is something else you would need to venture a guess as to why it isn't working, please let me know.
Turns out this is a bug with the Hibernate version we are using. What I had to do was to change embed-xml to true after Hibernate generated the HBM files. This was done using the "replace" ant function.