I started working on a new project using Playframework and thought to try using it with Ebean ORM. What i am wondering now is if Play with the Ebean implementation supports managed entities and if so ..how? Take this example method from the controller:
#Transactional
public Result changePassword() {
Long userId = Long.valueOf(session("id"));
User user = User.find.byId(userId);
user.setName("John Doe");
}
Is there any way to persist the changes to the database when the transaction ends? Currently what i am doing is calling user.save(). This is not much but working with JEE/JPA (and recently Dropwizard) i got used to have my entities changes persisted when the transaction ends.
No, I don't think Play natively supports something like auto save transaction as you want. Explicit save method is the only option.
Ebean.save(xyz);
General suggestion on your code, From Play 2.3.x, In your case, No need to annotate or explicitly mention the transaction, if Save is the only action on User EBean. By default each action on EBeans will be executed in separate transactions. Can specify the transaction explicitly if multiple actions need to be executed in single transaction.
Related
This question already has answers here:
Spring Data JPA Update #Query not updating?
(5 answers)
Closed 2 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Let's suppose to have this situation:
We have Spring Data configured in the standard way, there is a Respository object, an Entity object and all works well.
Now for some complex motivations I have to use EntityManager (or JdbcTemplate, whatever is at a lower level than Spring Data) directly to update the table associated to my Entity, with a native SQL query. So, I'm not using Entity object, but simply doing a database update manually on the table I use as entity (it's more correct to say the table from which I get values, see next rows).
The reason is that I had to bind my spring-data Entity to a MySQL view that makes UNION of multiple tables, not directly to the table I need to update.
What happens is:
In a functional test, I call the "manual" update method (on table from which the MySQL view is created) as previously described (through entity-manager) and if I make a simple Respository.findOne(objectId), I get the old object (not updated one). I have to call Entitymanager.refresh(object) to get the updated object.
Why?
Is there a way to "synchronize" (out of the box) objects (or force some refresh) in spring-data? Or am I asking for a miracle?
I'm not ironical, but maybe I'm not so expert, maybe (or probably) is my ignorance. If so please explain me why and (if you want) share some advanced knowledge about this amazing framework.
If I make a simple Respository.findOne(objectId) I get old object (not
updated one). I've to call Entitymanager.refresh(object) to get
updated object.
Why?
The first-level cache is active for the duration of a session. Any object entity previously retrieved in the context of a session will be retrieved from the first-level cache unless there is reason to go back to the database.
Is there a reason to go back to the database after your SQL update? Well, as the book Pro JPA 2 notes (p199) regarding bulk update statements (either via JPQL or SQL):
The first issue for developers to consider when using these [bulk update] statements
is that the persistence context is not updated to reflect the results
of the operation. Bulk operations are issued as SQL against the
database, bypassing the in-memory structures of the persistence
context.
which is what you are seeing. That is why you need to call refresh to force the entity to be reloaded from the database as the persistence context is not aware of any potential modifications.
The book also notes the following about using Native SQL statements (rather than JPQL bulk update):
■ CAUTION Native SQL update and delete operations should not be
executed on tables mapped by an entity. The JP QL operations tell the
provider what cached entity state must be invalidated in order to
remain consistent with the database. Native SQL operations bypass such
checks and can quickly lead to situations where the inmemory cache is
out of date with respect to the database.
Essentially then, should you have a 2nd level cache configured then updating any entity currently in the cache via a native SQL statement is likely to result in stale data in the cache.
In Spring Boot JpaRepository:
If our modifying query changes entities contained in the persistence context, then this context becomes outdated.
In order to fetch the entities from the database with latest record.
Use #Modifying(clearAutomatically = true)
#Modifying annotation has clearAutomatically attribute which defines whether it should clear the underlying persistence context after executing the modifying query.
Example:
#Modifying(clearAutomatically = true)
#Query("UPDATE NetworkEntity n SET n.network_status = :network_status WHERE n.network_id = :network_id")
int expireNetwork(#Param("network_id") Integer network_id, #Param("network_status") String network_status);
Based on the way you described your usage, fetching from the repo should retrieve the updated object without the need to refresh the object as long as the method which used the entity manager to merge has #transactional
here's a sample test
#DirtiesContext(classMode = ClassMode.AFTER_CLASS)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationConfig.class)
#EnableJpaRepositories(basePackages = "com.foo")
public class SampleSegmentTest {
#Resource
SampleJpaRepository segmentJpaRepository;
#PersistenceContext
private EntityManager entityManager;
#Transactional
#Test
public void test() {
Segment segment = new Segment();
ReflectionTestUtils.setField(segment, "value", "foo");
ReflectionTestUtils.setField(segment, "description", "bar");
segmentJpaRepository.save(segment);
assertNotNull(segment.getId());
assertEquals("foo", segment.getValue());
assertEquals("bar",segment.getDescription());
ReflectionTestUtils.setField(segment, "value", "foo2");
entityManager.merge(segment);
Segment updatedSegment = segmentJpaRepository.findOne(segment.getId());
assertEquals("foo2", updatedSegment.getValue());
}
}
I'm going to become mad with JPA...
I have a JAX-WS Webservice like that
#WebService
public class MyService
{
#EJB private MyDbService myDbService;
...
System.out.println(dmrService.read());
...
}
My EJB contains
#Stateless
public class MyDbService
{
#PersistenceContext(unitName="mypu")
private EntityManager entityManager;
public MyEntity read()
{
MyEntity myEntity;
String queryString = "SELECT ... WHERE e.name = :type";
TypedQuery<MyEntity> query = entityManager.createQuery(queryString,MyEntity.class);
query.setParameter("type","xyz");
try
{
myEntity= query.getSingleResult();
}
catch (Exception e)
{
myEntity= null;
}
return myEntity;
}
In my persistence.xml the mypu has transaction-type="JTA" and a jta-data-source
If I call the webservice, it's working. The entity is retrieved from the db.
Now, using an external tool, I'm changing the value of one field in my record.
I'm calling the webservice again and ... the entity displayed contains the old value.
If I'm deploying again, or if I'm adding a entityManager.refresh(myEntity) after the request, I have the good value again.
In #MyTwoCents answer, Option 2 is to NOT use your 'external' tool for changes, use your application instead. Caching is of more use if your application knows about all the changes going on, or has some way of being informed of them. This is the better option, but only if your application can be the single access point for the data.
Forcing a refresh, via EntityManager.refresh() or through provider specific query hints on specific queries, or by invalidating the cache as described here https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching#How_to_refresh_the_cache is another option. This forces JPA to go past the cache and access the database on the specific query. Problems with this are you must either know when the cache is stale and needs to be refreshed, or put it on queries that cannot tolerate stale data. If that is fairly frequent or on every query, then your application is going through all the work of maintaining a cache that isn't used.
The last option is to turn off the second level cache. This forces queries to always load entities into an EntityManager from the database data, not a second level cache. You reduce the risk of stale data (but not eliminate it, as the EntityManager is required to have its own first level cache for managed entities, representing a transactional cache), but at the cost of reloading and rebuilding entities, sometimes unnecessarily if they have been read before by other threads.
Which is best depends entirely on the application and its expected use cases.
Don't be mad its fine
Flow goes like this.
You fired a query saying where type="xyz"
Now Hibernate keeps this query or state in cache so that if you fire query again it will return same value if state is not changes.
Now you are updating detail from some external resource.
Hibernate doesnt have any clue about that
So when you fire query again it returns from catch
When you do refresh, hibernate gets detail from Database
Solution :
So you can either add refresh before calling get call
OR
Change the Table value using Hibernate methods in Application so that Hibernate is aware about changes.
OR
Disable Hibernate cache to query each time from DB (not recommended as it will slow down stuff)
Does an equivalent for the Hibernate filters exist in the JPA?
The following hibernate annotation can be for example used in order to define a filter:
#Entity
#FilterDef(name="minLength", parameters=#ParamDef( name="minLength", type="integer" ) )
#Filters( {
#Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
#Filter(name="minLength", condition=":minLength <= length")
} )
public class Forest { ... }
I would like to use something equivalent from JPA in order to restrict read access to some entities. How it can be done using clean JPA, without Hibernate annotations?
I didn't find any serious and reliable solution.
I analysed the "JPA Security" project. However, its home page was last updated two years ago, its last version is 0.4.0 and it doesn't seem to be a reliable solution. It's not a standard and it is not popular.
Other alternative in Hibernate which can be used in my case to restrict read access to an entity is the Hibernate Interceptor API - the following interface method can be implemented in order to append a SQL string which contains some additional conditions:
org.hibernate.Interceptor.onPrepareStatement(String sql)
or the following method can be overriden:
org.hibernate.EmptyInterceptor.onPrepareStatement(String sql)
I found out that there are some JPA event callbacks and annotations, e.g. #PostLoad. However, none of these can be used in my case, because I need something to restrict access to entities based on some conditions (user role).
Anyone knows how it can be done using JPA standards?
It seems to me that you are attempting to perform validations on entity objects. You have a few options to accomplish this.
The first would be to use the Java Validations API and its associated validations. This is the recommended approach with Java EE, of which JPA is a part. For example, you could write your entity class as follows:
#Entity
class Person {
#NotNull
#Size(min = 5, Max = 50)
String name;
}
Now, every time you attempt to persist an instance of Person, the JPA provider will automatically validate the instance, provided there is a Java Validator on the classpath. Validation errors will be thrown as runtime exceptions and can be used to rollback transactions. It is also possible to invoke a validator manually, collect any validation errors and transform them into user-friendly messages if required.
The other (probably dirty) option is to use the JPA Event Listeners, perform validations and throw an exception if a validation fails. This will terminate the JPA operation immediately and rollback any transactions.
Is it possible to stop hibernate from auto updating a persistent object?
#Transactional
public ResultTO updateRecord(RequestTO requestTO) {
Entity entity = dao.getEntityById(requestTO.getId());
// now update the entity based on the data in the requestTO
ValidationResult validationResult = runValidation(entity);
if(validationResult.hasErrors()) {
// return ResultTO with validation errors
} else {
dao.persist(entity);
}
}
Here is what happens in the code, I retrieve the entity which would be considered by hibernate to be in persistent state, then I update some of the fields in the entity, then pass the entity to validation. if validation fails, then don't udpate, if validation succeeds then persist the entity.
Here is the main issue with this flow: because I updated the entity for it to be used in the validation, it does not matter whether I call persist() method (on the DAO) or not, the record will always be updated because hibernate detects that the entity has been changed and flags it for update.
Keep im mind I can change the way i do validation and work around the issue, so I'm not interested in workarounds. I'm interested in knowing how i would be able to disable the hibernate feature where it automatically updates persistent objects.
Please keep in mind I'm using hibernates' implementation of JPA. so Hibernate specific answers dealing with hibernate specific API will not work for me.
I tried to look for hibernate configuration and see if I can set any configuration to stop this behavior but no luck.
Thanks
--EDIT ---
I couldn't find a solution to this, so I opted to rolling back the transaction without throwing any RuntimeException even though I'm in a declarative transaction using:
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
which works like a charm.
Configure FlushMode for your session.
http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/FlushMode.html
You can use EntityManager.clear() method after getting object from database.
http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#clear()
You can call the following code:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
Throw an exception if validation fails and have the caller handle that.
How can I force Hibernate to update an entity instance even if the entity is not dirty? I'm using Hibernate 3.3.2 GA, Hibernate Annotations and Hibernate EntityManager btw. I really want Hibernate to execute the generic UPDATE statement even if no property on the entity has changed.
I need this because some event listeners need to get invoked to do some additional work when the application runs for the first time.
Thanks!
ok - found it myself. This does the trick:
Session session = (Session)entityManager.getDelegate();
session.evict(entity);
session.update(entity);
For transients, you can check
if(session.contains(entity)) {
session.evict(entity);
}
session.update(entity);
session.evict(entity);
session.update(entity);
Good trick, but watch out for transient objects before putting this into some automation code. For transients I have then StaleStateObjectException
Try em.flush() which is used for EJB 3.0 entities, which also uses JPA similar to Hibernate 3.2.2 GA. If it doesn't work normally, use flush in transactions.