spring hibernate merge example - spring

I have a Spring 4 and Hibernate 5 back-end RESTful web-service. This works great and is all unit tested. The front-end is a SmartGWT 5.0p application which uses DataSources, not RestDataSources to communicate with the back-end.
The front-end SmartGWT 5.0p uses a listgrid to edit data, and then the ListGrid is attched to a datasource. Only the edited data in the ListGrid is sent back, not the entire row. If I could, I'd like to be able send backthe entire listgrid row with edited data, and the unedited data. If I could get an answer to that, that would be great.
Or, the alternate is we let SmartGWT only send back part of the data which is edited. This comes to the back-end as JSON and is changed into an Object/Entity. The controller/end-point is not in a session yet, but then we call a method in the service layer which is transactional.
So, then question becomes we have a detached object in a session in the method in the service layer. We have a detached object with a database primary key ... but it also has 1 or 2 fields of updated data, and now we want to merge that data back to the database. We can't call an update with this entity because with the partial data, some of the fields are being set to null. In reality, we want to pull back the item from the databae, update the edited fields, and then write the data back to the database.
I could do this all manually ... but do I have to? I expect there is a more graceful way to handle this.
Thanks!

This is only a partial answer:
I can make SmartGWT combine old values and new values with a link I found here:
SMARTGWT DataSource (GWT-RPC-DATASource) LISTGRID
And the code is as follows:
private ListGridRecord getEditedRecord(DSRequest request)
{
// Retrieving values before edit
JavaScriptObject oldValues = request
.getAttributeAsJavaScriptObject("oldValues");
// Creating new record for combining old values with changes
ListGridRecord newRecord = new ListGridRecord();
// Copying properties from old record
JSOHelper.apply(oldValues, newRecord.getJsObj());
// Retrieving changed values
JavaScriptObject data = request.getData();
// Apply changes
JSOHelper.apply(data, newRecord.getJsObj());
return newRecord;
}
This JSON string contains the new fields updated, and the old fields. When this json string is sent back to the RESTful back end, the Jackson Mapper creates an entity and puts all the fields in, this is essentially a detached entity. It's an object outside of the session, but the id resides in the database.
Because I have a complete entity, I can all an update, and that works.
Problem solved.
BUT, I'd still like to find out an elegant solution for taking a detached entity, get the original record from the database, and then merge these two objects, and then finally update the record.
In the Service layer in Spring which has a transaction, and creates the session,
a manual process, which I don't want to do might look something like this:
1) get the id from the updatedEntity
2) get that attachedEntity from the database using that id
3) compare the fields
if( updatedEntity.updateField1 != null )
{ attachedEntity.setField1(updatedEntity.updateField1) }
If I had to do step 3 for multiple fields,
that's not very elegant.
4) Update attachedEntity to the database, because it now has updated fields.
So, again, an elegant solution to fix this might be helpful. Thanks!

Related

Retrieve the deleted record spring JPA

I am working on a spring application.
We have a specific requirement where when we get a specific event, we want to look it up in the DB. If we find the record in the DB, then we delete it from DB, create another event using the details and trigger it.
Now my concern is:
I do not want to use two different calls, one to find the record and another to
delete the record.
I am looking for a way where we can delete the record using a custom
query and simultaneously fetch the deleted record.
This saves two differnet calls to DB, one for fetch and another for delete.
What I found on the internet so far:
We can use the custom query for deletion using the annotation called #Modifying. But this does not allow us to return the object as a whole. You can only return void or int from the methods that are annotated using #Modifying.
We have removeBy or deleteBy named queries provided by spring. but this also returns int only and not the complete record object that is being deleted.
I am specifically looking for something like:
#Transactional
FulfilmentAcknowledgement deleteByEntityIdAndItemIdAndFulfilmentIdAndType(#Param(value = "entityId") String entityId, #Param(value = "itemId") String itemId,
#Param(value = "fulfilmentId") Long fulfilmentId, #Param(value = "type") String type);
Is it possible to get the deleted record from DB and make the above call work?
I could not find a way to retrieve the actual object being deleted either by custom #Query or by named queries. The only method that returns the object being deleted is deleteById or removeById, but for that, we need the primary key of the record that is being deleted. It is not always possible to have that primary key with us.
So far, the best way that I found to do this was:
Fetch the record from DB using the custom query.
Delete the record from DB by calling deleteById. Although, you can now delete it using any method since we would not be requiring the object being returned by deleteById. I still chose deleteById because my DB is indexed on the primary key and it is faster to delete it using that.
We can use reactor or executor service to run the processes asynchronously and parallelly.

Spring data JPA save() return less/incorrect child and parent association mapping fields [duplicate]

I'm developing a RESTful webservice with spring-data as its data access layer, backed by JPA/Hibernate.
It is very common to have relationships between domain entities. For example, imagine an entity Product which has a Category entity.
Now, when the client POSTs a Product representation to a JAX-RS method. That method is annotated with #Transactional to wrap every repository operation in a transaction. Of course, the client only sends the id of an already existing Category, not the whole representation, just a reference (the foreign key).
In that method, if I do this:
entity = repository.save(entity);
the variable entity now has a Category with only the id field set. This didn't surprise me. I wasn't expecting a save (SQL insert) to retrieve information on related objects. But I need the whole Product object and related entities to be able to return to the user.
Then I did this:
entity = repository.save(entity);
entity = repository.findOne(entity.getId());
that is, retrieve the object after persisting it, within the same transaction/session.
To my surprise, the variable entity didn't change anything. Actually, the database didn't even get a single select query.
This is related with Hibernate's cache. For some reason, when in the same transaction, a find does not retrieve the whole object graph if that object was previously persisted.
With Hibernate, the solution appears to be to use session.refresh(entity) (see this and this). Makes sense.
But how can I achieve this with spring data?
I would like to avoid to create repetitive custom repositories. I think that this functionality should be a part of spring data itslef (Some people already reported this in spring data's forum: thread1, thread2).
tl;dr
References between entities in the web layer need to be made explicit by using links and should not be hidden behind semi-populated object instances. References in the persistence layer are represented by object references. So there should be a dedicated step transforming one (the link) into the other (the fully populated object reference).
Details
It's an anti-pattern to hand around backend ids as such and assume the marshaling binding doing the right thing. So the clients should rather work with links and hand those to the server to indicate they want to establish a connection between an already existing resource and one about to be created.
So assuming you have the existing Category exposed via /categories/4711, you could post to your server:
POST /products
{ links : [ { rel : "category", href : "/categories/4711" } ],
// further product data
}
The server would the instantiate a new Product instance, populate it with additional data and eventually populate the associations as follows:
Identify properties to be populated by looking up the link relation types (e.g. the category property here.
Extract the backend identifier from the given URI
Use the according repository to lookup the related entity instance
Set it on the root entity
So in your example boiling down to:
Product product = new Product();
// populate primitive properties
product.setCategory(categoryRepository.findOne(4711));
productRepository.save(product);
Simply posting something like this to the server:
POST /products
{ category : {
id : 1, … },
…
}
is suboptimal for a lot of reasons:
You want the persistence provider to implicitly persist a Product instance and at the same time 'recognize' that the Category instance referred to (actually consisting of an id only) is not meant to be persisted but updated with the data of the already existing Category? That's quite a bit of magic I'd argue.
You essentially impose the data structure you use to POST to the server to the persistence layer by expecting it to transparently deal with the way you decided to do POSTs. That's not a responsibility of the persistence layer but the web layer. The whole purpose of a web layer is to mitigate between the characteristics of an HTTP based protocol using representations and links to a backend service.

How to use Hazelcast with MapStore

I am using Hazelcast as caching Solution for my application.
My application has few inserts and updates to the database and these needs to be synced to Cache also.
I want to use MapStore functionality so that when I do IMap.put(), Hazelcast takes care of persisting the Object in underlying Db and also update its cache.
In the overridden store implementation, I want to call my DAO in following way to persist the Data.
public void store(Long key, Product value)
{
log.info("Storing Data for Employee {} in Database using DataStore ", value);
Long employeeId = employeeDao.create(value);
value.setId(employeeId );
}
There are few issues listed below:-
1) In put call, I want to use "key" as the "employeeId", but this is generated only after insertion happens for this record in the Db. So how do I put into the Cache when I don't have the Id.? I want Hazelcast to use the "id" generated as part of store method call (or any other way) as the key to my Object.
Imap.put(key,new Employee("name_of_Employee","age_of_employee"))
2) The MapStore implementation's store method returns a void so I cannot return the Id generated for this Object to the Client. How can I achieve this?
I tried using MapEntryListeners on the Map but the entry added callback does not return new Object. I also added PostProcessingMapStore interface to my MapStore but could not get the new Value back to client.
Please advice
You have 2 options:
1) Generate the employeeId outside of the database. You can use the IdGenerator from Hazelcast to do this.
2) If you must let the database generate the id, then you need to put the Employee in the cache manually AFTER it has been stored in the database.

Double instances in database after using EntityManager.merge() in Transient Method

I am new with Spring, my application, developed with Spring Roo has a Cron that every day download some files and update a database.
The update is done, after downloading and parsing the files, using merge(),
an Entity class Dataset has a list called resources, after the download I do:
dataset.setResources(resources);
dataset.merge();
and dataset.merge() does the following:
#Transactional
public Dataset Dataset.merge() {
if (this.entityManager == null) this.entityManager = entityManager();
Dataset merged = this.entityManager.merge(this);
this.entityManager.flush();
return merged;
}
I expect that doing dataset.setResources(resources); I would overwrite the filed resources, and so even the database entry would be overwritten.
But I get double entries in the database: every resource appear twice, with different IDs (incremental).
How can I succed in let my application doing updates and not insert? A naive solution would be delete manually the old resource and then call merge(); is this the way or is there some more smart solution?
This situation occurs when you use Hibernate as persistence engine and your entities have version field.
Normally the ID field is what we need for merging a detached object with its persistent state in the database, but Hibernate takes the version field in account and if you don't set it (it is null) Hibernate discards the value of ID field and creates a new object with new ID.
To know if you are affected by this strange feature of Hibernate, set a value in the version field, if an Exception is thrown you got it. In that case the best way to solve it is the data to parse contain the right value of version. Another ways are to disable version checking (see Hibernate ref guide to know about it) or load persistent state before merging.

how can i update an object/entity that is not completely filled out?

I have an entity with several fields, but on one view i want to only edit one of the fields. for example... I have a user entity, user has, id, name, address, username, pwd, and so on. on one of the views i want to be able to change the pwd(and only the pwd). so the view only knows of the id and sends the pwd. I want to update my entity without loading the rest of the fields(there are many many more) and changing the one pwd field and then saving them ALL back to the database. has anyone tried this. or know where i can look. all help is greatly appreciated.
Thx in advance.
PS
i should have given more detail. im using hibernate, roo is creating my entities. I agree that each view should have its own entity, problem is, im only building controllers, everything was done before. we were finders from the service layer, but we wanted to use some other finders, they seemed to not be accessible through the service layer, the decision was made to blow away the service layer and just interact with the entities directly (through the finders), the UserService.update(user) is no longer an option. i have recently found a User.persist() and a User.merge(), does the merge update all the fields on the object or only the ones that are not null, or if i want one to now be null how would it know the difference?
Which technologies except Spring are you using?
First of all have separate DTOs for every view, stripped only to what's needed. One DTO for id+password, another for address data, etc. Remember that DTOs can inherit from each other, so you can avoid duplication. And never pass business/ORM entities directly to view. It is too risky, leaks in some frameworks might allow users to modify fields which you haven't intended.
After the DTO comes back from the view (most web frameworks work like this) simply load the whole entity and fill only the fields that are present in the DTO.
But it seems like it's the persistence that is troubling you. Assuming you are using Hibernate, you can take advantage of dynamic-update setting:
dynamic-update (optional - defaults to false): specifies that UPDATE SQL should be generated at runtime and can contain only those columns whose values have changed.
In this case you are still loading the whole entity into memory, but Hibernate will generate as small UPDATE as possible, including only modified (dirty) fields.
Another approach is to have separate entities for each use-case/view. So you'll have an entity with only id and password, entity with only address data, etc. All of them are mapped to the same table, but to different subset of columns. This easily becomes a mess and should be treated as a last resort.
See the hibernate reference here
For persist()
persist() makes a transient instance persistent. However, it does not guarantee that the
identifier value will be assigned to the persistent instance immediately, the assignment
might happen at flush time. persist() also guarantees that it will not execute an INSERT
statement if it is called outside of transaction boundaries. This is useful in long-running
conversations with an extended Session/persistence context.
For merge
if there is a persistent instance with the same identifier currently associated with the session, copy the state of the given object onto the persistent instance
if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance
the persistent instance is returned
the given instance does not become associated with the session, it remains detached
persist() and merge() has nothing to do with the fact that the columns are modified or not .Use dynamic-update as #Tomasz Nurkiewicz has suggested for saving only the modified columns .Use dynamic-insert for inserting not null columns .
Some JPA providers such as EclipseLink support fetch groups. So you can load a partial instance and update it.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/AttributeGroup

Resources