Update by id of an entity attribute which is another entity - java

When I need to update a relationship of an entity, normally I have something like this:
XEntity entityToSave = ....
YEntity relatedEntity = relatedEntityRepository.findById(relatedEntityId);
entityToSave.setRelatedEntity(relatedEntity);
repository.save(entityToSave);
I would like to skip the findById of the related entity, because as I understand the id is everything what JPA should need to make the update.
So, I want like this:
XEntity entityToSave = ....
entityToSave.setRelatedEntity(
YEntity.builder().id(relatedEntityId).build()
);
repository.save(entityToSave);
Someway JPA should be aware that I just want to set the related entity (without update any attribute of it)
Do you know any way to achieve this?
UPDATE:
I want to avoid inject the relatedEntityRepository. As I have the id of the related entity. which is everything that jpa should know to update the relatioship

When using Spring repository, use getOne(..). It is Spring data equivalent to EntityManager.getReference(..). So like:
entityToSave.setRelatedEntity(repo.getOne(relatedEntityId));
Method getOne kind a "stores" a reference for entity by the id you provide. It does not fetch the entity - so it is lazy - until you access properties of referenced (your relatedEntity) entity (except id that is not needed to fetch anyway).
When referencing (your related) entity is saved then reference to referenced entity is saved also and usually without ever fetching the referenced entity (so if you do not modify referenced entity).
See this also
There usually just is no point to "avoid injecting" something especially singleton (Spring default) beans. You could achieve this behavior with #Modifying and some native query on repository method or make it a bit "lighter" by injection entity manager and use that to handle all the stuff but it would be more complex and obfuscating so IMO you would shoot your own leg that way.

Related

Creating a JPA (Hibernate) proxy and set the Primary key later

Well, I'm working on a library where I need to create a JPA reference of some serialized entity objects.
The time I need to create the entity reference I don't have the ID field value so I somehow first need to create the proxy and then set the id. So I cannot use the
entitymanager.getReference
Do you guys have any suggestions?
You cannot do that. Without an id an entity is in "detached" state, which means it's not governed by hibernate. You need to fetch it from db (or get reference), persist or make managed in other way, so it's not possible.

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 .

JPA+Hibernate force JPA not to use Proxies on Lazy loading

We are using JPA + Hibernate.
I have some Many-to-one mappings which are lazy loaded.
In Service, I Initiallize the Many-to-one objects by calling their getter method. but proxy gets assigned to parent VO and not actual VO Object.
My Question is, Is there any way in JPA to force to use no proxy Strategy.
My limitation here is i cant use Hibernate Objects or annotaions like #LazytoOne etc.
thanks in advance.
You cannot prevent Hibernate from using proxy objects there due to the fact that somehow it has to guarantee it's a lazy relation.
You have multiple choices:
Trigger the initialization Hibernate.initialize(parent.getChild()). Note that this is not the best way to do it and this also requires an active transaction.
Fetch the relation when fetching the entity itself. This can be done with the Fetch Joins. JPQL/HQL/Criteria API are capable of doing this.
Use read-only projections which contains only the data you need. For this particular case you can use Spring Data JPA as it comes with such a feature.
I suggest you to go with either option 2 or 3 as they are the most effective ways to do this.
Furher reading about lazy-loading here.

How to update an entity property if it is used in a relationship?

Persisting of, updates to and deleting of an entity can be tracked with #Pre/PostPersist, #Pre/PostUpdate and #Pre/PostDelete JPA annotations. I'd like to change an entity property if it has been used in a relationship, i.e. if another entity has used it as a value of a relationship field or added to a relationship collection.
Using #PrePostLoad is difficult because it's hard to exclude loads which are unrelated to usage in relationships.
I'd like to use a pura JPA/provider-portable solution, but I'm curious about provider specific solutions as well.
The concrete idea is let the user create and persist entities (e.g. instances of contact information) in a form and then associate them with another entity created in another form (e.g. a document with a sender property). The (already persisted) available entities for associating are displayed in a table. This table should be sortable by a counter for the most frequent or a timestamp for most recent usage of the entities.
I'm using JPA 2.1 (EclipseLink 2.6.4 currently).
I handled the update in the UI by adding a Storage interface which wraps EntityManager and allows to register pre and post persistence callback (functional interfaces are a real blessing) like
#FunctionalInterface
interface Callback {
void callback(EntityManager e);
This suggestion has been proposed by another user, but then deleted apparently.

Hibernate manyToOne filter on base entity

I have an entity "Event" that has a ManyToOne relationship with the entity "Organization". So an Organization can have multiple events.
What I originally wanted to do was to filter the entity Event using a property of the Organization entity. So basically when I fetch events, only return the events that have an Organization.code= :codeParam.
To accomplish that I implemented a hibernate filter with :
#FilterDef(name="codeFilter", parameters=#ParamDef( name="codeParam", type="string" ) )
...
#ManyToOne
#JoinColumn(name="Organization_Id")
#Filter(name="codeFilter", condition=" code = :codeParam")
private Organization organization;
...
Filter hibernateFilter = sess.enableFilter("codeFilter");
hibernateFilter.setParameter("codeParam", "hola");
Unfortunately according to a post from the Hibernate Team on the hibernate forums, this is not possible :
A Hibernate data filter does not change the multiplicity of an association. By definition it therefore does not filter many-to-one, one-to-one, or any load() or get() operation.
What is it supposed to do, return NULL instead of an instance? NULL does not mean FILTERED, it means NULL. You guys are using filters wrong.
So my question is : is there any way to filter the base entity ("Event") with a condition on the entity from a manyToOne relationship (Organization.code= :codeParam)?
I need this to be enforced every time there is a fetch of events, so a solution using the already existing hibernate filters or something similar would be greatly appreciated.
EDIT1: The question is a simple example of what needs to be done on a significantly bigger scale. Basically, we want to add security to all our Entities and their own nested Entities through the use of a globally defined filter on a Unix permissions row that all our tables have.
WARNING: Do not do this, it is dependent on Hibernate internals and prone to breaking on schema changes, and possibly on variations in individual query setup.
Set Hibernate to show its generated sql, run the query you want to filter (in this case, loading some Event objects), and check what name it assigns to the join used for fetching the related Organization. For example, the generated sql might include inner join Organization someNameHere on this_.Organization_Id = someNameHere.OrganizationId. Then apply the filter, not to the association, but to the Event class, with condition "someNameHere.code = :codeParam".
This is, unfortunately, the only way I've been able to find to filter one class by the properties of an associated class.
I'm trying to make a more robust solution, but it's a complex issue and I'm still in the research stage for that. I expect it will use code generation (through an annotation processor) and programmatic modification of Hibernate's mapping information on startup, but I'm not sure what else yet.

Categories