Audit fields for AppEngine entities - java

Looking for suggestions for an efficient way to maintain basic audit fields for entities in AppEngine for Java (via objectify). The #PrePersist attribute looks like a good option for various date fields (dateCreated, dateModified, dateDeleted) but I'm also looking to store the ID of the user who created, modified, deleted the entity as well. Is this best left to the data access layer?

If you need to store records with more than just the dates you mention you probably want to create an audit object and use #Embed to store it inside of the objects you're auditing. Then use #PrePersist to update this object. That will give you a consistent audit framework across objects.

IMHO #PrePersist is an ok place to perform this.
You also might want to use objectify's polymorphism - this way you could have a base class containing all audit fields and perform saving. Than all classes needing audit would just extend this base class.

Related

How to properly update entities using REST and JPA/Hibernate

I have entity Document, which has lots of columns, one-to-one, one-to-many and many-to-many mappings to some other entities.
Example:
Document:
id,
title,
body,
authors,
viewers,
...
Using REST, I want to update some particular document, controller receives serialized Document object, calling EntityManager's merge method persists null results to the database if controller received for instance only body , then I want the body to be updated only, but merge deletes records for title, authors and viewers and etc.
I understand that it is a standard behavior of EntityManager, but I am asking what is the most preferred technique to do updates on entities without receiving whole entity from front-end or some other endpoint. Should I load the entity from database using the id I received and set MANUALLY all of the fields and then save to database or should I use another technique.
I don't have any problem with writing manually all of the setters to copy the changes, but entities are really big in size with lots of relations. Asking for best practice in this case.
I know about DTOs but I want alternate approach when using entities for controllers and service methods.
For entity partial update, you will need to use either criteria api or jpql ... if you are using older versions with no criteria update or old query parser where jpql update is not allowed you will have to read from database first, update then insert again .... you can also make use of updatable=false for columns that should be only set on creation (like CREATION_DATE) and there is also a nice feature in hibernate called #DynamicUpdate which I haven't tried but looks brilliant ... It only updates the modified field (check Vlad's post here) ... concerning the DTO DP , I you might always need to use if you want to hide / modify some data from the client regardless to the way you store the data ... and it's always a good way to separate concerns (but comes with the mapping headache between domain & DTO objects which is much released thanks to spring converters)
There are two options one is update query, which works fine but you may feel
you are loosing some hibernate features and simplicity of the code. Else you can do it in Hibernate way like below
AuditorBean auditorBean = (AuditorBean) session.get(AuditorBean.class, AuditorBean.getId());
auditorBean.setFirstName("aa");
auditorBean.setLatName("bb");
auditorBean.setTrainLevel("ISO");
auditorBean.setAccessLevel(4);
Here you should not call any method like saveOrUpdate() or merge().
object is attached with transaction, so object is flushed and committed at the end of the transaction automatically .

Best practice for Hibernate lazy properties initialization in MVC?

Let's say I use some entity, in pseudocode: Article { id, author, text, date } with all properties initialized lazily. I have repository method:
#Transactional
Article loadArticle(int id) {
return articeRepository.find(id);
}
which is used by different controllers. PreviewController requires author and date. ViewController requires text and date.
Should I pass boolean parameters initAuthor, initText, initDate to loadArticle() method to call Hibernate.initialize() for each property there? Or should I move #Transactional to controllers' methods? What are the best practices dealing with lazy initialization?
If you are aiming to have a highly performant data access layer, then you should keep one thing in your mind: every use-case is different thus needs different kind of data.
What I wanted to suggest with this is that you want to have different methods for different use-cases, which fetches only the data it needs.
There are multiple ways to do this:
Fetching the entity relation with a fetch join
Create read-only projections
I prefer the latter as it clearly shows that it's for showing data rather than modifying it.
For projections, Spring Data JPA can help as it has an out-of-the-box solution for it which is basically defining an interface.
If you use Hibernate.initialize() or any other way to trigger loading an entity relation, practically you will trigger a database query. If you think about let's say 100 entities, that means you will execute 101 queries. Use fetching or read-only projections.

How to merge input from a web service to a JPA entity

I'm trying to figure out the best way to use JPA in the context of a restful web service. The input comes in as JSON and I can use Jackson/JAX-RS to convert that to a POJO. This gets passed to a service where I need to somehow merge into a JPA entity.
These are the options I've found so far with pros and cons.
1. JPA merge()
The first thing I tried was probably the simplest. The GET action returns the JPA entity which is easily serialized into JSON. On the update the object is passed back is JSON which can be used to populate a detached entity. This can be saved to the DB using the JPA merge() method.
Pros
Simple architecture with less code duplication (i.e. no DTO's)
Cons
As far as I can tell this only works if you pass the whole model around. If you try to hide certain fields, like the maybe the password on a User entity, then the merge thinks you're trying to set these fields to null in the DB. Not good!
2. DTO's using JPA find() and dozer
Next I thought I'd look at using data transfer objects. Apparently an anti-pattern but worth a look. The service now creates a DTO instance based on the entity and it is this DTO that is serialized to JSON. The update then gets the entity from the DB using a find() method and the values need to be copied across from the DTO to the entity. I tried automating this mapping using the dozer framework.
Pros
You don't have to return the entire model. If you have certain fields you don't want to be updated you can leave them off the DTO and they can't be copied to the entity by mistake. Using dozer means you don't have to manually copy attributes from dto to entity and vice versa.
Cons
It feels like repeating yourself when writing the DTO's. Somehow you have to map between entities and DTO's. I tried to automate this with dozer but it was a bit disappointing. It was nulling out things it shouldn't have been and to get full control you have to write xml.
3. DTO's using manual merge
A third way would be to abandon dozer and just copy the properties across from the DTO to the entity in the service. Everybody seems to say anti-pattern but it's pretty much how every non-trivial application that I've seen in the past has worked.
Summary
It seems to be a decision between keeping things simple for the developer but not having control over the input/output or making a more robust web service but having to use an anti-pattern in the process...
Have I missed anything? Perhaps there's an elusive alternative?
Using JPA merge looks the simplest, cleanest and with very less effort but as correctly discovered creates problems with detached entity attributes set to null.
Another problem which turned out to be big in one of my experiences was that if you rely on JPA merge operation you must be using Cascade feature as well.
For simple and less nested relation this works reasonably well, but for deeply nested domain objects and lots of relations, this becomes a big impact on performance. The reason being that the ORM tool (Hibernate in my experience) upfront caches the SQL to load the merge entity ( 'merge path' in Hibernate parlance) and if the nesting is too deep with Cascade mappings the joins in the SQL becomes too big. Marking realtions Lazy does not help here as the merge path is determined by the Cascades in relations. This problem becomes apparent slowly as your model evolves. Plus the prospect of angry DBA waving a huge join query on our face prompted us to do something different :-)
There is an interesting issue related to Hibernate regarding Merging of Lazy relations still unresolved (actually rejected but the discussion is very enjoyable to read) in Hibernate JIRA.
We then moved towards the DTO approach where we refrained from using merge and relied on doing it manually. Yes it was tedious and required the knowledge of
what state is actally coming from the detached entity, but to us it was worth. This way we do not touch the Lazy relations and attributes not meant to change. and set only what is required. The automatic state detection of Hibernate does the rest on transaction commit.
This is approach I am using:
suppress serialization of certain fields with XmlTransient annotation
when updating the record from the client, get the entity from the database and use ModelMapper with custom property mapping to copy the updated values without changing the fields that are not in the JSON representation.
For example:
public class User {
#Id
private long id;
private String email;
#XmlTransient
private String password;
...
}
public class UserService {
...
public User updateUser(User dto) {
User entity = em.find(User.class, dto.getId());
ModelMapper modelMapper = new ModelMapper();
modelMapper.addMappings(new UserMap());
modelMapper.map(userDto, user);
return user;
}
}
public class UserMap extends PropertyMap<User, User> {
protected void configure() {
skip().setPassword(null);
}
}
BeanUtils is an alternative to ModelMapper.
It would be nice if these libraries could recognize the XmlTransient annotation so the programmer can avoid creating the custom property map.

JPA2/Hibernate - Stop lazy loading?

I'm having a problem where JPA is trying to lazily load my data when I don't want it to. Essentially what is happening is I'm using a Service to retrieve some data, and when I go to parse that data into JSON, the JSON library is triggering hibernate to try and lazily load the data. Is there any way to stop this? I've given an example below.
// Web Controller method
public String getEmployeesByQuery(String query) {
Gson gson = new Gson();
List<Employee> employees = employeeService.findEmployeesByQuery(query);
// Here is where the problem is occurring - the gson.toJSON() method is (I imagine)
// using my getters to format the JSON output, which is triggering hibernate to
// try and lazily load my data...
return gson.toJSON(employees);
}
Is it possible to set JPA/hibernate to not try and lazily load the data?
UPDATE: I realize that you can use FetchType.EAGER - but what if I don't want to eager load that data? I just want to stop hibernate from trying to retrieve more data - I already have the data I want. Right now whenever I try and access a get() method hibernate will throw a "no session or session is closed" error, which makes sense because my transaction was already committed from my service.
Thanks!
There are several options:
If you always need to load your collection eagerly, you can specify fetch = FetchType.EAGER in your mapping, as suggested in other answers.
Otherwise you can enable eager fetching for particular query:
By using JOIN FETCH clause in HQL/JPQL query:
SELECT e FROM Employee e JOIN FETCH e.children WHERE ...
By using fetch profiles (in JPA you can access Hibernate Session via em.unwrap(Session.class))
You really have two options:
You can copy the data from employee to one that is not being proxied by hibernate.
See if there is a way to not have the toJSON library reflect the entire object graph. I know some JSON libraries allow you to only serialize some properties of an object to JSON.
Personally I would think #1 would be easier if your library only uses reflection.
As others have stated, this is not an issue with JPA/hibernate but rather with the json serialization library you are using. You should instruct gson to exclude the properties you don't want traversed.
Yes:
#*ToMany(fetch=FetchType.EAGER)
I suggest you to make a fetched copy of the entities you want to use outside of a transaction. That way, the lazy loading will occur from within a transaction and you can pass to Gson a plain, not enhanced, POJO.
You can use Doozer to do this. It is very flexible and through a little configuration (read you'll gonna loose your hair configuring it) you can even retrieve only partially the data you want to send to Gson.
You could always change the fetch attribute to FetchType.EAGER, but it is also worth considering if you have your transactions have the right scope. Collections will be correctly loaded if they are accessed within a transaction.
Your problem is that you are serializing the data. We ran into the same sort of problem with Flex and JPA/Hibernate. The trick is, depending on how much you want to mangle things, either
Change your data model to not chase after the data you don't want.
Copy the data you do want into some sort of DTO that has no relationships to worry about.
Assuming you're using Hibernate, add the Session-in-view filter....its something like that, it will keep the session open while you serialize the entire database. ;)
Option one is what we did for the first big project we did, but it ruined the data access library we had for any sort of general purpose use. Since that time we've tended more toward option two.
YMMV
The easy and straight forward thing to do is create new Data classes (something like DTO)
use Hibernate.isInitialized() to check if the object is initialized by hibernate or not.
I am checking gson if i can override anything. I will post it here if I find anything new.

easy way to make many pojo into one pojo

Am having a registration form which has multiple pages. So, I am mapping one page to one pojo. Finally, when I processing with database, I want to make it as single pojo to commit. Any idea to simplify this model.
Thanks :)
You can create a wrapper POJO which holds your other POJO's with additional helper methods in the master POJO.
What is wrong with sending multiple POJOs to your service level to commit to the database. Koekiebox's suggestion of a wrapper POJO will work, but also will add another place to make changes to if you add or remove POJOs.
If the data truly belongs together why not increase the number of fields in your POJO and use just one for your form and database.

Categories