Dealing with EntityNotFoundException - java

I am creating simple REST API. I want to create an object via post method. Object contains other object. When I want to post it, I am receiving EntityNotFoundException which is thrown when nested object does not exist.
Code of object that I want to post:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Book {
private String title;
#ManyToOne
private Author author;
#Id
#Column(unique = true)
private String isbn;
}
Service of this object:
#Service
#RequiredArgsConstructor
public class BookServiceImpl implements BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
#Override
public Book save(Book book) {
try {
Author byId = authorRepository.getById(book.getAuthor().getId());
} catch (EntityNotFoundException e) {
authorRepository.save(book.getAuthor());
}
return bookRepository.save(book);
}
}
After using post method I get this error:
javax.persistence.EntityNotFoundException: Unable to find com.jakubkolacz.qualificationTask.domain.dao.Author with id 0
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:163) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:216) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
I thought that using try catch to check if object exist, and saving author if necessary will help but it did not.
My question is where should I add some code to solve the problem. I understand why it is happening but do not know how to resolve it. The necessary thing is that I can not create service to add authors manually, they have to be added to repo only during adding new book.

The problem is that the save operation is not being cascaded down to the author object. You should add a cascade type inside ManyToOne annotation:
#ManyToOne(cascade = CascadeType.ALL)

Exception handling in Spring
If you are specifically wondering how to handle exceptions in Spring, then I would highly recommend THIS tutorial.
Entity Creation
First I would like to point out two minor problems with your entity creation.
1)#ManyToOne : while it is not necessary, I always like to annotate a many-to-one relationship with the #JoinColumn annotation. It just acts as a simple and friendly visual reminder that (assuming your relationship is bidirectional) this side is the owner of the relationship(has the foreign key)
2)#Id : as it currently stands, the JPA provider(lets assume hibernate) assumes that you the developer are taking care of assigning a unique identifier to the id field. Granted, this is sometimes neccessary when dealing with old legacy databases. However, if you are not dealing with a legacy database, I would recommend that you delete #Column(unique = true) and the String value to replace them with:
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long isbn;
#GeneratedValue will allow the system to automatically generate a value for isnb field.
strategy = GenerationType.IDENTITY tells the underlying database to handle the uniqueness and the auto incrementation in a way specific to the relational database.
Long instead of String because it can hold a larger number of bytes.
Service implementation
I have a few things to say about the BookServiceImpl class but first, good job on implementing an interface with BookService most people forget to program to an interface.
1) Single Responsibility
You are using both BookRepository and AuthorRepository which is of course fine(If it works it works). However, moving forward you should be weary not to add too many dependencies to one class. If you do so, you are breaking the Single Responsibility principle, which makes code harder to test and refactor.
2) Try and catch
The code inside your try catch blocks is a little confusing, especially since you have not shown the Author entity class. However, I am assuming you logic goes like this: if the author does not exist, save the author. Lastly save and return the book. Now you are correct in thinking that you handle the exceptions in the catch block. However, there is quite a lot to question here and only so little code to go on.
My overall recommendations
1) Break this method up : This method is trying to do three things at once. Create one method for saving the book, one for looking for the author and one for saving the author. This will allow for greater code reuse moving forward.
2) Read up on CascadeType : Specifically PERSIST, that might help you with your issues. Also, look into a many-to-many relationship as it is not uncommon for multiple books to have multiple authors.

Related

Why is an entity being automatically saved without calling persist when using foreign generation strategy in bidirectional one-to-one mapping?

I have been practicing one-to-one mapping in hibernate and don't understand this particular case. I have to say, the program is working fine and as I intended, but apparently I can omit a perist() call and it still works smoothly. The fact that it's working is good, but I want to know exactly why the call is optional. Let me write some details:
This is the user class, which is supposed to be the owning side of the mapping:
#Data
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE)
private Long id;
private String name;
#OneToOne
private Ticket ticket;
public User() {}
public User(String name) {
this.name=name;
}
}
And this is the ticket class that's supposed to be the dependent one:
#Data
#Entity
public class Ticket {
#Id
#GeneratedValue(generator="foreignGenerator")
#GenericGenerator(name="foreignGenerator", strategy="foreign",
parameters=#org.hibernate.annotations.Parameter(name="property", value="user"))
private Long id;
#OneToOne(optional = false, mappedBy="ticket")
#PrimaryKeyJoinColumn
private User user;
public Ticket() {
}
public Ticket(User user) {
this.user=user;
}
}
I am trying to test the "shared primary key" strategy in one-to-one mapping. As you can see I have set up the generator with foreign strategy, which is supposed to make Ticket's id the same as it's corresponding User's id.
#Bean
CommandLineRunner loadData() {
return args->{
EntityManager em=emf.createEntityManager();
em.getTransaction().begin();
User user=new User("Test User");
Ticket ticket=new Ticket(user);
//em.persist(user);
user.setTicket(ticket);
em.persist(ticket);
em.getTransaction().commit();
em.close();
//We don't have to call persist on user
};
}
}
This program runs perfectly. Uncommenting the line which calls persist on user makes no difference. I am assuming that persisting ticket, which has it's user property set, automatically saves the user as well. Therefore, the reason it makes no difference is that no matter if user is getting saved or not, it will get persisted when we call ticket.
I want to know if my assumption is correct and any additional links to articles/documentation would be greatly appreaciated. Especially I am wondering about this part that I said above-"I am assuming that persisting ticket, which has it's user property set, automatically saves the user as well." I couldn't find anything that would confirm or deny this. I know that the "shared primary key" approach in one-to-one mapping is the only use case of "foreign" generation strategy, so there are not a lot of posts about it, and whatever posts are there are getting overshadowed by "foreign key" during the search.
Any help regarding this or any other issue that might be wrong with the code provided above would be appreciated. Thanks for taking your time to read this
The JPA specification states this behavior is wrong:
Looking at the 3.0 release:
section "3.2.2. Persisting an Entity Instance" implies user is unmanaged after your persist (you can check with the em.contains method).
Section "3.2.4. Synchronization to the Database" covers the flush/commit which states:
• If X is a managed entity, it is synchronized to the database.
..
◦ For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the cascade element value cascade=PERSIST or cascade=ALL:
▪ If Y is new or removed, an IllegalStateException will be thrown by the flush operation (and the transaction marked for rollback) or the transaction commit will fail.
User is new, so this should be resulting in an exception. That it works might be a glitch in how Hibernate is handling the #PrimaryKeyJoinColumn annotation (speculation on my part) and custom "foreignGenerator".
This is not a pattern I'd suggest you rely on, and should instead call persist to avoid inconsistencies with the behavior on other mapping setups.

Improving JPA entity classes for existing DB schema

I am attempting to implement a Hibernate/JPA2 solution over an existing schema, which cannot be changed. Here is a minimal example of the existing schema:
CREATE TABLE REASON (
REASON_CODE CHAR(1),
REASON_DESCRIPTION CHAR(50))
CREATE TABLE HEADER (
REASON_CODE CHAR(1),
OTHERFIELD1 CHAR(40),
OTHERFIELD2 CHAR(40) )
Normally this would be the "correct" way from a DB perspective: Link REASON to HEADER by the REASON_CODE. However it's presenting me with an awkward problem in Java and I'm not sure of the best way to solve it. I've modeled these entities as follows:
#Entity
#Table(name="REASON")
public class Reason implements java.io.Serializable {
#Id
#Column(name="REASON_CODE", unique=true, nullable=false, length=1)
private Character reasonCode;
#Column(name="REASON_DESCRIPTION", nullable=false, length=25)
private String reasonDescription;
}
#Entity
#Table(name="HEADER")
public class Header implements java.io.Serializable {
#ManyToOne
#JoinColumn(name = "REASON_CODE", nullable = false)
private Reason reason;
#Column(name="OTHERFIELD1")
private String otherField1;
#Column(name="OTHERFIELD2")
private String otherField2;
}
Once again, as far as I can tell, this is "correct" from a Java perspective - linking Header to Reason with a reference.
The problem is that when I need to use one of these Reason values in my code I wind up with awkward syntax like:
Reason r = reasonService.findOne('X'); // X is the REASON_CODE in the database record
// Do some processing with variable r
Or this:
header.setReason(reasonService.findOne('X'));
Ideally I could implement Reason as an enum like:
public enum Reason {
X_MARKSTHESPOT("X"),
C_MEANSSOMETHINGELSE("C"),
F_MEANSATHIRDTHING("F") ;
private String code;
private Reason(String code) {
this.code = code;
}
}
And then simply have this in my code:
header.setReason(Reason.X_MARKSTHESPOT);
But from what I understand that is not possible with JPA, which offers only EnumType.STRING (basically the name) or EnumType.ORDINAL (even worse, the index in the enum list). A possible way around this would be JPA 2.1's Converter, but I have never used it. I have also read here (in one of the answers) that a Hibernate User Type might be useful. One of our programmers has solved this in another app by writing two complete classes - an enum class for internal use and a "shadow" class which iterates through the enum and syncs the records in the database on every startup. But this seems like a kludgey way to do it. What is the best way to handle this, bearing in mind that the database schema cannot be changed?

What is appropriate way of creating objects with One-to-Many relationship using Objectify and RequestFactory?

What is appropriate way of creating objects with One-to-Many relationship using Objectify and RequestFactory? I've read documentation for these libraries, and also reviewed number of sample projects such as listwidget and gwtgae2011. All of them use #Embedded annotation which is not what I want because it stores everything within one entity. Another option according to documentation would be to use #Parent property in child classes. In my example (getters/setters removed for simplicity) I have entities Person and Organization which defined as
#Entity
public class Person extends DatastoreObject
{
private String name;
private String phoneNumber;
private String email;
#Parent private Key<Organization> organizationKey;
}
and
#Entity
public class Organization extends DatastoreObject
{
private String name;
private List<Person> contactPeople;
private String address;
}
Now if I understood documentation correctly in order to persist Organization with one Person I have to persist Organization first, then set organizationKey to ObjectifyService.factory().getKey(organization) for Person object and then persist it. I already don't like that I have to iterate through every child object manually but using RequestFactory makes everything is more convoluted due to presence of proxy classes. How would I define Organization and OrganizationProxy classes - with Key<> or without it ? Will I have to define something like this in Organization ?
public void setContactPeople(List<Person> contactPeople)
{
for (int i = 0; i < contactPeople.size(); ++i)
{
DAOBase dao = new DAOBase();
Key<Organization> key = dao.ofy().put(this);
contactPeople.get(i).setOrganizationKey(key);
}
this.contactPeople = contactPeople;
}
And how would I load Organization with its children from Datastore ? Will I have to manually fetch every Person and fill out Organization.contactPeople in #PostLoad method ?
It seems like I'll have to write A LOT of maintenance code just to do what JPA/JDO does behind the scene. I simply don't get it :(
Am I missing something or it's the only way to implement it ?
Thanks a lot for answers in advance!!!
You need to make it as #Parent only when you going to use it in transaction against all Person in this Organization. I'm sure it's not what you want.
It's enough to save just private Key<Organization> organizationKey, and filter by this field when you need to find Person for specified Organization
As about loading all referenced objects - yes, it is, you have to load it manually. It's pita, but it's not a lot of code.
Also, there is a different way to store this relationship, if your organization are small enough, and consists of few hundreds of people. At this case you can have List<Key<Person>> contactPeopleKey;, and load all this people by existing Key, manually, it much be much faster than loading by new Query

How to implement a 3 Many-to-Many relationship with Hibernate?

I'm not 100% sure this is only a Hibernate issue as this might be a more abstract decision but I'll give it a try.
Since the problem description is a bit lengthy I'll first state that what I'd like to do is see if I can change the implementation to something which more resembles a Best practice implementation then this.
I have 3 entities, relevant to this issue: Workstation (ws), Employee and Organization-unit(org-unit).
An Employee can belong to one org-unit.
An Org-unit can hold many employees.
A Workstation is used to display data of an Org-unit(in general), Of an Org-unit and a specific employee in it and an employee which does not belong to an org-unit.
Currently, for various reasons which were out of my control, we do not use any associations between the entities in Hibernate or via DB-Constraints but we just use Columns which logically serve as Foreign-Keys.
We currently have an additional table which has 4 columns:Id,WSId,EmployeeId,OrgUnitId.
This allows a WS to refer to an orgunit (where employeeId is null),to an employee without an org-unit (orgunitId is null) or to an employee and org-unit (where none are null).
I'd like to be able to know:
1.Given a WS, which employees is it following and which org-units and how (i.e., alone, with an employee? which?)
2.Given an employee, which WS are monitoring it.
3.Given an org-unit, which WS are monitoring it and how (i.e., alone, with an employee? which?)
This issues relates to the Presentation layer as it dictates the view will be generated BUT it is a part of the domain model as a user, will use, an interface to manipulate these monitoring mappings and so these mappings are a part of the domain model.
I'm not sure if what I have is not the least evil among options, and I would greatly appreciate comments and suggestions.
EDIT From one of the answers I think it is not clear enough that a WS can display data for many such mappings at the same time, in a mixture of the above sorts (org-unit, employee etc.)
OK, I don't know how to implement this on the database side, but here is an Entity Model that should cover the relationship you are talking about.
Edit:
This is a new version in response to your comments. Now every WorkStation has n bindings each of which can have employee or orgunit or both (use DB constraints to ensure they don't have neither).
You can also access the bindings per orgunit and per employee, which should make the above queries much easier:
#Entity
public class OrgUnit{
#OneToMany(mappedBy="orgUnit")
private Set<Binding> bindings;
}
#Entity
public class Employee{
#OneToMany(mappedBy="employee")
private Set<Binding> bindings;
}
#Entity
public class Binding{
#ManyToOne(optional = true)
private Employee employee;
#ManyToOne(optional=true)
private OrgUnit orgUnit;
#ManyToOne(optional=false)
private WorkStation owner;
}
#Entity
public class WorkStation{
#OneToMany(mappedBy="owner")
private Set<Binding> bindings;
}
Sample Client code:
public Set<WorkStation> getWorkstationsPerEmployee(final Employee employee){
final Set<WorkStation> workStations = new HashSet<WorkStation>();
for(final Binding binding : employee.getBindings()){
WorkStation workStation = binding.getOwner();
if(workStation!=null)
workStations.add(workStation);
}
return workStations;
}
Sounds like all you really need is a nullable FK on Employee to OrgUnit, and two nullable FKs on WS to both Employee and OrgUnit. To see which WS are monitoring an employee, just get all the WS with matching emp_id columns. Same with the WS monitoring an OrgUnit, possibly with the additional stipulation of emp_id being null or not (depending on if you need to handle those situations separately). No idea where "patients" fits in, you didn't give any details about that.

JPA cascade update error. Am I doing this the wrong way?

I'm using JPA on a SWING application in JAVA that connects to an Apache DERBY embedded database. I use Netbeans as my IDE and use many of the "supposedly" helpful templates. My problem is simple, but it's difficult for me to explain so I will paste the relevant code here and try to explain at the bottom.
#Entity
public class AnioLectivo implements Serializable, Comparable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
#OneToMany(mappedBy = "anioLectivo", cascade=CascadeType.ALL)
private List<Compensatorio> compensatorios;
...
}
#Entity
public class Compensatorio implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
#ManyToOne
private AnioLectivo anioLectivo;
...
}
These two are the entities that i want to persist.
public class AnioLectivoJpaController
{
public void edit(AnioLectivo anioLectivo) throws NonexistentEntityException,
Exception
{
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
AnioLectivo persistentAnioLectivo = em.find(AnioLectivo.class,
anioLectivo.getId());
...
List<Compensatorio> compensatoriosOld =
persistentAnioLectivo.getCompensatorios();
List<Compensatorio> compensatoriosNew = anioLectivo.getCompensatorios();
...
List<Compensatorio> attachedCompensatoriosNew = new ArrayList<Compensatorio>();
for (Compensatorio compensatoriosNewCompensatorioToAttach : compensatoriosNew) {
compensatoriosNewCompensatorioToAttach =
em.getReference(compensatoriosNewCompensatorioToAttach.getClass(),
compensatoriosNewCompensatorioToAttach.getId());
attachedCompensatoriosNew.add(compensatoriosNewCompensatorioToAttach);
}
compensatoriosNew = attachedCompensatoriosNew;
anioLectivo.setCompensatorios(compensatoriosNew);
...
}
This is a class that netbeans generates using the annotations of the entity AnioLectivo that i pasted before. As you can see, i only pasted the code relevant to the problem to keep it simple because i know thanks to the debug tool of netbeans that the problem is here.
Now I'll try to explain exactly what happens.
I create instances of AnioLectivo in one part of the program and persist them ok. Then in another part i must create and add instances of Compensatorio to the Compensatorio's List in an instance of AnioLectivo. Now I want to save this modification, which I assume is made using the edit method in the class AnioLectivoJpaController and I found this error:
java.lang.IllegalArgumentException: An instance of a null PK has been incorrectly provided for this find operation.
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerImpl.findInternal(EntityManagerImpl.java:309)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl.getReference(EntityManagerImpl.java:176)
at org.sigeb.local.service.dao.jpa.AnioLectivoJpaController.edit(AnioLectivoJpaController.java:113)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp.guardarCambios(AdministrarCursosPopUp.java:574)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp.jBGuardarCambiosActionPerformed(AdministrarCursosPopUp.java:394)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp.access$1000(AdministrarCursosPopUp.java:44)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp$11.actionPerformed(AdministrarCursosPopUp.java:204)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
...
the problem, as I see it, occurs in this line of code in the edit method of AnioLectivoJpaController:
em.getReference(compensatoriosNewCompensatorioToAttach.getClass(),
compensatoriosNewCompensatorioToAttach.getId());
Why? Well if you see the entities, I have defined that the id of all entities are to be generated by the persistence unit, but this only happens when the entity itself is told to persist. As I create the Compensatorio's instances I never set the id explicitly and when it arrives to that line I quoted up there, compensatoriosNewCompensatorioToAttach.getId() returns null.
It's my understanding that ORM's like JPA have Persistence by Reachability, that allows that if an object A is related to an object B, persisting A also persists B. But in this case it seems like it's implemented in a very inconvenient way(at least for me), because it forces me to persist every object of my collection explicitly when it would be more usefull to persist the object that owns that collection and then the objects in that collection be persisted automatically
Is there something I'm doing wrong?, maybe I should face this problem from another angle, but I don't know how, or if any, what angle?. Why does the people of netbeans make that template that way, why is it useful to execute that method to try to search the objects in the DB and bring it to the persistence context, do i need to persist every object myself? if that's so why do they claim to have Persistence by Reachability if the persistence can only be made in one direction only.
I'm clearly wrong in this, what I'm seeking it's a coherent explanation of how would have to be explicited the relationship between those entities(if i actually did a mistake in the way i created them, because in every book and tutorial i read it's done like that) to make it work so i don't need to persist every object of that collection, or, if i need to drop that template from netbeans and make the code for all the CRUD operations myself, i will like to hear advice on how is convenient to proceed in this case.
It seems to be you can call em.merge(anioLectivo) insted of all this code.

Categories