We are migrating to spring & hibernate from struts1.x and JDBC.
Facing issue while adding multiple rows in jsp (like mapped properties in struts1.x) based on user preferences (Ex: Adding/deleting employees to Manager) in spring.
In service layer, getting Manager Object (as persistent object returned by hibernate )then displaying manager object in JSP. Employee row will be deleted by using java script/jquery from html form by user delete action, upon form submission spring does not delete in the respective employee from the list of employees of Manager object (model attribute). I have worked on some examples without hibernate where the object is being deleted from the list and works well but not in the hibernate prepared object.
ex: lets say Manager object have 3 employees as List when displaying on screen, when user will delete one employee row and submitted then spring needs to populate the Manager object with two employee objects as list since one employee is deleted by user in UI.
I suspect that, this behavior with PersistentBag implementation of Hibernate?
Anybody experienced this problem earlier? Any ideas would be greatly appreciate.
It might depends on how the pojo is declared..
Sure you are deleting a manager, but how is the manager connected to the employee?
If on the manager you have a Employee Object, you should have
#OneToOne(cascade=CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#JoinColumn(name="EMPLOYEE_ID", nullable = false)
private Employee employee;
This way, if you delete the manager object, it will cascade delete the Employee object...
Either your "cascade" is enforced via db, or it must be enforced via annotation.. if you're not doing either, of course nothing will happen...
Related
I've base entity class named Person, it has Manager field, this field implements #ManyToOne relationship sharing the same base table (person). In the code, we've explicitly want this relationship to not be cached, hence we decalred it with #Noncacheable annotation,
so we when we try to fetch person related record, expectation is to fetch manager info from datasource not from cache, but in the response we'll see the manager returns empty, we observed behaviour that the manager field is also getting L2 cached. As a workaround solution, we add annotation as #Cache(alwaysrefresh=true) , Post that manager field returns value.
Can someone pls explain above behaviour and the underhood working mechanism of #Noncacheable annotation.
As says on To initialize or not initialize JPA relationship mappings? is good practice to initialize the relations on JPA mapping.
But into web architecture (Spring MVC), where the entities will be send as JSON, usually with a RESTfull API, the relations will be omitted on the serialization and it will be fetched to the server using its path (i.e employees/[id]/projects).
If we have:
class Employee {
#ManyToMany //Employee owner of relation
protected List<Project> projects=new ArrayList<Project>(0);
}
If from the client we want to update only the Employee name, the client send the JSON to the server (HTTP PUT), it is deserialized and employee.projects will be initialized as empty collection. When the EntityManager save, it will update the properties (right) and the projects (Employee is owner side) DELETING the existing projects.
A alternative is use the DIY merge pattern. "Instead of invoking EntityManager.merge we invoke EntityManager.find to find the existing entity and copy over the state ourselves". This workaround requires specific entity code on update.
What is the best way to solve it?
Background
I am using Play Framework(Java) to store data. Play Framework uses Ebean to convert classes into data that can be stored in a a database.
Issue
I am currently having trouble fetching relational data completely. I have a User and a UserEmail model. The User can own multiple UserEmails.
User Model Code
User Email Model Code
When I try and fetch a User, the User data is fetched correctly, however the UserEmails are not.
Fetching Code
When I specifically add fetch("emails") to the fetch code
User.find.fetch("emails").where().eq("userId", testUserId).findUnique();
It seams like it at least gets the emails. However when I try and show them via
return ok(Json.toJson(retrievedTestUser));
I get This Error
Question
Is there some way I can make Play Framework/Ebean automatically fetch the emails without adding fetch("emails") to every query? Maybe an annotation?
How do I resolve the error above? I get why it is thrown, but how can I fix it? Is there any way to have it only fetch one level deep?
I have found solution to above problem. Every entity should have id.
User class has field annotated with #Id but UserEmail has not.
After adding #Id annotation above email field of UserEmail class user is fetched properly and its email list is not empty.
#Id
public String email;
One more thing that I spotted in your code:
When you are creating bidirectional relation then you should use mappedBy attribute on one side to indicate that these are two ends of one relation and not two separate relations. So there should be:
#OneToMany(mappedBy="user", cascade = CascadeType.ALL)
#Constraints.Required
public List<UserEmail> emails;
I am following the NetBeans E-commerce tutorial - on the 9th Tutorial which is about Integrating Transnational Business Logic
Where they show how create the OrderManager class with placeOrder() Method - and the method is transactional which involves three tables - first customer, then customer_order and finally orderedItem using em.persist().
but the em.persist() method is not persisting for customer - but it will persist for customer if I manually supplied the customer id manually into the code (hard code).
but for the customer_order it will not persist even after persisting the customer by manual id provision and using em.flush();
I googled and couldn't seem to find way out. P.S. The Entity class is generated with Netbeans wizard - and the id generation strategy IDENTITY
The em.persist() was not persisting because the #NotNull annotation on the id fields was not allowing null - as I am working on Netbeans.
so removing those #NotNull or commenting them out on the entity class gets the job done.
infact I learned this fact from the last post of the following link.
Hibernate Auto Increment ID
I have a couple of objects that are mapped to tables in a database using Hibernate, BatchTransaction and Transaction. BatchTransaction's table (batch_transactions) has a foreign key reference to transactions, named transaction_id.
In the past I have used a batch runner that used internal calls to run the batch transactions and complete the reference from BatchTransaction to Transaction once the transaction is complete. After a Transaction has been inserted, I just call batchTransaction.setTransaction(txn), so I have a #ManyToOne mapping from BatchTransaction to Transaction.
I am changing the batch runner so that it executes its transactions through a Web service. The ID of the newly inserted Transaction will be returned by the service and I'll want to update transaction_id in BatchTransaction directly (rather than using the setter for the Transaction field on BatchTransaction, which would require me to load the newly inserted item unnecessarily).
It seems like the most logical way to do it is to use SQL rather than Hibernate, but I was wondering if there's a more elegant approach. Any ideas?
Here's the basic mapping.
BatchQuery.java
#Entity
#Table(name = "batch_queries")
public class BatchQuery
{
#ManyToOne
#JoinColumn(name = "query_id")
public Query getQuery()
{
return mQuery;
}
}
Query.java
#Entity
#Table(name = "queries")
public class Query
{
}
The idea is to update the query_id column in batch_queries without setting the "query" property on a BatchQuery object.
Using a direct SQL update, or an HQL update, is certainly feasible.
Not seeing the full problem, it looks to me like you might be making a modification to your domain that's worth documenting in your domain. You may be moving to having a BatchTransaction that has as a member just the TransactionId and not the full transaction.
If in other activities, the BatchTransaction will still be needing to hydrate that Transaction, I'd consider adding a separate mapping for the TransactionId, and having that be the managing mapping (make the Transaction association update and insert false).
If BatchTransaction will no longer be concerned with the full Transaction, just remove that association after adding a the TransactionId field.
As you have writeen, we can use SQL to achieve solution for above problem. But i will suggest not to update the primary keys via SQL.
Now, as you are changing the key, which means you are creating alltogether a new object, for this, you can first delete the existing object, with the previous key, and then try to insert a new object with the updated key(in your case transaction_id)