Exception while lazily loading a collection from entity - jsf-2

I fear that I miss a very basic point, but I'm stuck at the moment, hopefully someone can point my eyes starring to hard at it to the right one...
I try to go through my application setup step by step for make myself clear (hoping people won't get bored before they reach the end of the posting):
I have a session scoped CDI component serving as a handler for a JSF 2.0 view. It holds an entity manager, a list of objects and a special single object:
#Named
#SessionScoped
public class EventHandler implements Serializable {
#PersistenceContext
private EntityManager em;
private List<MyEvent> events;
private MyEvent currentEvent;
...
When the view requests the list for displaying a table, it fills the list by querying the database:
Query query = em.createQuery("select e from MyEvent e");
events = (ArrayList<MyEvent>) query.getResultList();
The view shows this in a data table and provides a link to an action method within the handler:
<h:dataTable value="#{eventHandler.events}" var="_var">
...
<h:commandLink action="#{eventHandler.linkAction(_var)}"> ... </h:commandLink>
The action method stores the reference:
public void setCurrentEvent(MyEvent currentEvent) {
this.currentEvent = currentEvent;
...
Within the entity used in the collection and references above, there'a relationship which gets loaded lazily by default:
#ManyToMany(mappedBy="supportedServices")
public Set<MyEntity> getSupportingEntities() {
...
Now, when being in the detail view and trying to access this relationship by doing:
#{eventHandler.currentEvent.supportingEntities...}
I get a org.hibernate.LazyInitializationException telling me that the session is closed.
Shouldn't the handler be able to load the requested relationship at a later point in the 2nd view, when the handler is session scoped and loaded the references via a query?

Hum, I think this is because the persistenceContext, event if it is a member of a session scoped bean, is not session scoped.
When the view is called the first time, a persistence context is created, the entities(events) are loaded and the datatable is populated. Then the persistence context is flushed, closed and the response is sent to the client. This all happen in the same http request.
But when you then call the details view, another http request is issued, and another persistence context is created, and your reference to "currentEvent" is no more attached to the last persistence context. Hence the LazyInitializationError (the entity must be managed to lazy load).
Solutions could be :
Use an extended persistence context (explained here).
Eager fetch the relation :
#ManyToMany(mappedBy="supportedServices", fetch=FetchType.EAGER)
Merge the detached instance of currentEvent before using it in the details view :
entityManager.merge(currentEvent);

Related

persisting MVC data to ORM

Java or dotNet world is rich of open source frameworks and libraries. We all like to use Spring and Hibernate almost everywhere.
Everyone agrees that hibernate is a very handy tool.
What Hibernate can do ? well, Basically - Hibernate can track our domain objects changes and persist only modified data to database, that is it.
Basically, That is everything we want. I want to load some records from database, do some modifications to them, and call transaction.commit(), and all modifications get persisted, instantaneously.
That is excelent, right !
But how about web world ? In web applications database session must be closed.
I cannot load some domain objects and wait for user to do modifications through HTTP, and persist those objects after modifications.
We have to use detached objects or DTO. How it works ?
User makes modifications in HTML browser, spring Mvc automatically thransfers those HTML modifiactions to our customized DTO objects using MVC model binding,
then we do some programming effort to transfer modifications from DTO objects to hibernate domain objects and only then we persist them.
For example - we have a web form that updates Customer address, and another form which updates customer details.
We must have two different business layer methods - UpdateAddress() and UpdateDetails(), both methods must accept some kind of DTO,
one represents address information, the other represents details infprmation.
We also have custom logic that transfers data from those 2 DTO to the domain class 'Customer'.
Yes, of course, instead of DTO objects we could reuse our domain classes. But it does not make it simpler.
In both cases we will still have to implement custom logic that transfer modifications to persistent objects,
I cannot persist detached object rightaway, because usually domain classes have lots and lots of properties representing numerous relations, for ex. Customer has - Orders property. When I update customer address I don't want to update its orders.
Is there a beautifull universal way to mapping modifications from mvc model to domain objects without writing a lot of custom code and without risk of overwriting too many fields ?
It's good practice to have a data access layer, which translates into having a repository for each domain object / entity. Furthermore, all repositories share common code so you you naturally have an abstract repository:
public abstract class AbstractRepository<E extends BaseModel> implements Repository<E> {
#PersistenceContext
private EntityManager entityManager;
private Class<E> entityClass;
public AbstractRepository(Class<E> entityClass) {
this.entityClass = entityClass;
}
protected EntityManager getEM() {
return entityManager;
}
protected TypedQuery<E> createQuery(String jpql) {
return createQuery(jpql, entityClass);
}
protected <T> TypedQuery<T> createQuery(String jpql, Class<T> typeClass) {
return getEM().createQuery(jpql, typeClass);
}
#Override
public E merge(E entity) {
return getEM().merge(entity);
}
#Override
public void remove(E entity) {
getEM().remove(entity);
}
#Override
public E findById(long id) {
return getEM().find(entityClass, id);
}
}
It's also good practice to have a service layer where you are to create, update and delete instances of an entity (where you could pass through a DTO to the create and update methods if you so desire).
...
#Inject
private CustomerRepository customerRepository;
public Customer createCustomer(CustomerDto customerDto) {
Customer customer = new Customer();
customer.setEmail(customerDto.getEmail());
...
return customerRepository.merge(customer);
}
public Customer updateCustomerAddress(Customer customer, String address) {
customer.setAddress(address);
return customerRepository.merge(customer);
}
...
So it's up to you how many update methods you want. I would typically group them into common operations such as updating the customer's address, where you would pass the customer Id and the updated address from the front end (probably via ajax) to your controller listening on a specific endpoint. This endpoint is where you would use the repository to find the entity first by Id and then pass it to your service to do the address update for example.
Lastly you need to ensure that the data actually gets persisted, so in Spring you can add the #Transactional annotation either to you Spring MVC controller or to your service that does the persisting. I'm not aware of any best practices around this but I prefer adding it to my controllers so that you're always guaranteed to have a transaction no matter what service you are in.

Session and view scoped beans - Values being overwritten

#SessionScoped
public SessionClass{
// Buyer is a view scoped class
private List<Buyer> sessionObject = new ArrayList<Buyer>();
}
When updating a input field buyer.fname. The list is also updated.
Should I change the Buyer class to session scope also.
This has nothing to do with JSF scopes, but everything with the object oriented nature of Java. Apparently the view scoped Buyer instance represents exactly the same reference as the item in the list of the session scoped bean (it's however beyond me how you coded it like that; it would have been explainable if Buyer is actually a JPA entity).
You should be creating a copy of the Buyer instance instead or detach the entity if it's indeed a JPA entity.

Cannot reference ViewScoped Managed bean from PhaseListener in JSF 2.1 app

I've tried every solution from a couple dozen google searches: getRequestMap, ElResolver, evaluateExpressionGet and so on. Nothing, absolutely nothing, works. I get null every time. Here is the relevant code:
#ManagedBean(name="readerBean")
#ViewScoped
public class ReaderBean implements Serializable {...
And in the PhaseListener:
public void beforePhase(PhaseEvent event) {
if (event.getPhaseId() == PhaseId.RESTORE_VIEW) {
ReaderBean r = null; //The Managed Bean
try {
FacesContext fctx = FacesContext.getCurrentInstance();
r=(ReaderBean) fctx.getExternalContext().getRequestMap().get("readerBean");
r=(ReaderBean) fctx.getELContext().getELResolver().getValue(fctx.getELContext(), null, "readerBean");
r=(ReaderBean) fctx.getApplication().getExpressionFactory().createValueExpression(fctx.getELContext(), "#{readerBean}", ReaderBean.class).getValue(fctx.getELContext());
r=(ReaderBean) fctx.getApplication().evaluateExpressionGet(fctx, "#{readerBean}", ReaderBean.class);
Nothing works!!!
As to the request map approach, it fails because a view scoped bean is not stored in the request scope. It's instead stored in the view scope. As to the other approaches, they fail because the view scoped bean is stored in the view and thus only available after the view has been restored. However, you're trying to get it before the view has been restored. This is a chicken-egg problem.
You need to revise your approach. Perhaps the bean needs to be a request scoped one? Perhaps the logic needs to be executed at a different phase? Perhaps the logic needs to be performed in the bean itself instead? Etc.
As the concrete functional requirement for which you thought that this is the right solution is unmentioned in the question, I can't point you in the right direction.

Best practises in MVC for not disposing the object context?

I have an Entity Framework class called Student. It has a list of Classes. Now, everytime I (from my view) refer to ViewBag.Student.Classes, it fails with an object disposed exception, because my controller looks like this:
using(var myObjectContext = new ModelContainer()) {
ViewBag.Student = myObjectContext.UserSet.OfType<Student>().FirstOrDefault(s => s.Id == ActiveStudentSignedIn);
}
Now, I know I could just pass in the student's classes in the viewbag too, but that would increase complexity when using strong-typed partial views that rely on a student and its details.
I think it would be wrong to not having the "using" keyword there, because wouldn't that leave up too much garbage for the garbage collector to collect?
I'm obviously doing something wrong. But what?
There are two ways to solve this:
Use eager loading (Include method in query) and pass all data you need in view from your controller action directly. Currently you receive exception because your view is trying to trigger lazy loading and execute another queries to database but the context is already disposed.
Extend lifetime of your context = don't create context per action. Create single context per controller (new instance is created for every request) and dispose context in controller's Dispose method. You can also inject the context into controller from outside - dependency injection but that would require some other infrastructure.
You could try eagerly loading associations:
ViewBag.Student = myObjectContext
.UserSet
.Include("Classes")
.OfType<Student>()
.FirstOrDefault(s => s.Id == ActiveStudentSignedIn);

enforcing ObjectStateManager entry deletion on page leave

I have a edited RESTful wizard based upon Shoulders of Giants | A RESTful Wizard Using ASP.Net MVC… Perhaps? . This wizard has a CANCEL button which, when pressed, fires the code below.
// If the user cancels, drop out altogether
if (!string.IsNullOrEmpty(CANCEL_BUTTON)) {
Session.Remove(VACANCYWIZARD_SESSION_KEY);
repository._entities.ObjectStateManager.GetObjectStateEntry(inProgressVacancyWizard.Vacancy).Delete();
return this.RedirectToAction("Index", "Home");
}
Now, to be able to call SaveChanges() after the cancel button I have to manually delete the entry from the wizard from my ObjectStateManager. But when you cancel the wizard by just manually returning to the home page it stays in and a next call to _entities.SaveChanges() will throw an exception that it cannot Save the object, from the wizard progress to the database, since it is still in the object state.
Note that in between the steps of the wizard I do not save anything to the database. I keep it in session state retrieving it each step:
NewVacancy inProgressVacancyWizard = Session[VACANCYWIZARD_SESSION_KEY] as NewVacancy;
Somehow, however, the inProgressVacancyWizard.Vacancy does appear in the ObjectStateManager so I have to delete it else I will get errors about incomplete Vacancies models while the _entities.SaveChanges() is called for another object.
Is there a way to cover for this problem?
//edit
After some reading I have found out that the fundaments of my repository are not good. As found here. Currently I'm doubting to implement the option mentioned in "One ObjectContext instance per business transaction" in the same article. Would that be a wise thing? I would like to hear some more about it since it will be a major refactor.
public static Repository Instance
{
get
{
if (instance == null) {
instance = new Repository();
}
return instance;
}
}
#region Constructor: Repository()
/// <summary>
/// Constructor
/// </summary>
private Repository()
{
_entities = new DBModelEntitiesNew2();
}
It seems like you are using a single ObjectContext instance across multiple requests. Don't do that. It will cause you nothing but misery. It makes your web server stateful. Dispose the ObjectContext after the response is rendered (we do it, indirectly, from Controller.Dispose), and new up a new one for the next request.

Resources