Hibernate Criteria taking off associations - java

I have a class Usuario. User have association with UsuarioPerfil:
public class Usuario{
/*Attributes*/
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_usuario_perfil", referencedColumnName = "id", foreignKey = #ForeignKey(name = "fk_usuario_id_usuario_perfil"))
#Getter
#Setter
private UsuarioPerfil usuarioPerfil;
}
public class UsuarioPerfil{
/*Attributes*/
}
I am performing queries using the Criteria, as follows:
Session sessao = this.getEntityManager().unwrap(Session.class);
sessao.createCriteria(Usuario.class).list();
However, in some cases wish list does not come in the data UsuarioPerfil entity, only the User. How can I accomplish this using Hibernate Criteria?
Note: I know this is possible using Hibernate or JPA Query

I don't believe you can explicitly do what you are asking with the Hibernate Criteria API because it is generally accepted practice to make associations LAZY and set them to EAGER on a case-by-case basis.
Therefore, change your mapping to use fetch = FetchType.LAZY and then in the cases where you need the association in your query, specify it as:
criteria.setFetchMode("usuarioPerfil", FetchMode.JOIN);
If you have access to JPA's EntityGraph annotations, I would strongly suggest you look into those as well. At a minimum, you can at least look at Hibernate's FetchProfile concept because those go along way to defining fetch strategies by name which helps keep code and queries much cleaner.

Related

Hibernate select with birectionnal mapping

On a bidirectional relationship beetwen two entities (a ControlTable made up of ControlSteps), i'm simply trying by different ways to request a ControlTable by knowing the collection ControlSteps of it. I know that it's not recommended to have this bidirectionnal mapping but i need to know each childs of a parent, and the parent for each child.
I configured it like this in ControlTable class:
#OneToMany(mappedBy = "controlTable",cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Fetch(FetchMode.JOIN)
private Set<ControlStep> controlSteps;
And like this for ControlStep class :
#ManyToOne(optional=false, fetch=FetchType.LAZY)
#JoinColumn(name="ctrl_table_id", referencedColumnName = "id")
private ControlTable controlTable;
When i use the default JPA query findAll(), it's not working to get the list of ControlTables (or only one) because it's requesting recursively the parent in the child's parent (infinite response).
In another way, itried to put all in LAZY loading, with an HQL query fetching the childs, but the result is the same.
Do you have any idea of how to get these collections without problems?
Thank you very much by advance
Found it. The problem was Spring Data Rest and JSON transformation, for more details :
Infinite Recursion with Jackson JSON and Hibernate JPA issue

Controlling lazy/eager loading of #Formula columns dynamically

We have a few entities with a bunch of properties annotated with Hibernate's #Formula annotation. The SQL snippets in the annotations mainly run scalar sub-queries (e.g. COUNT queries). As an example, we have a one-to-many relationship hierarchy that's four levels deep: A <- B <- C <- D (where <- marks a one-to-many association). Pretty often when fetching an entity of type A, we'd like to know the amount of associated entities of type D. For this we use a #Formula-annotated property in A.
As we don't need these values every time, we've declared the #Formula properties as lazy-loaded (we've enabled Hibernate's bytecode enhancement to make this possible). But for some queries, we'd like to load these properties eagerly. We often load hundreds of entities of type A in one query, and it'd be important performance-wise to control the eager/lazy loading of these properties dynamically. We already use JPA's entity graphs to control which properties get loaded eagerly for certain queries, but entity graphs don't seem to work here. Even if we list the #Formula properties in the entity graph, they're still loaded lazily.
Is it possible to control lazy/eager loading of #Formula columns dynamically on a per query basis? We're currently restricted to the JPA Criteria Query API, and named queries are not a possibility here.
Update:
The properties in question are not associations to other entities, but just some calculated values. This means that e.g. fetch profiles don't apply here, as they're only applicable to entity associations (or at least that's how I understood the Hibernate manual). Here's an example of one of our #Formula properties:
#Entity
public class A {
#Basic(fetch = FetchType.LAZY)
#Formula("(select count(*) from entity_D_table where ...)")
private int associatedDCount;
...
}
You could use the Critria api to make it return a DTO instead of an Entity.
In your criteria query use a Projection to select only the column you need.
ProjectionList properties = Projections.projectionList();
properties.add(Projections.property("id").as("id"));
properties.add(Projections.property("name").as("name"));
properties.add(Projections.property("lazyField").as("lazyField"));
criteria.setProjection(properties);
criteria.setResultTransformer(new AliasToBeanResultTransformer(MyEntityDTO.class));
That way the select query will only contains the fields you ask, whatever the mapping EAGER or LAZY.
You can try to have a look at Hibernate's fetch profiles https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch20.html#performance-fetching-profiles.
You can for example annotate an entity like that
#Entity
#FetchProfile(name = "country_states", fetchOverrides = {
#FetchProfile.FetchOverride(entity = Country.class, association = "states", mode = FetchMode.JOIN)
})
public class Country implements Serializable {...
and activate the JOIN mode when querying, like this:
session=getSession();
session.beginTransaction();
//enable fetch profile for EAGER fetching
session.enableFetchProfile("country_states");
As shown in http://www.concretepage.com/hibernate/fetchprofile_hibernate_annotation
It turns out it's not hard to pull this off without having to resort to bytecode instrumentation.
Create a "formula" entity mapped to the same table:
#Entity
#Table("A")
public class ACounts {
#Id
private Long id;
#Formula("(select count(*) from entity_D_table where ...)")
private int dCount;
public int getDCount() {
return dCount;
}
}
Then in your parent entity, A, use #ManyToOne to relate lazily to this "formula" entity:
#Entity
public class A {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id", nullable = false, insertable = false, updatable = false)
private ACounts counts;
public ACounts getCounts() {
return counts;
}
...
}
Now the count query will only be issued when the count is requested (i.e. it's lazy!):
A a = ...
// lazily invoke count query now:
a.getCounts().getDCount()
ref: https://stackoverflow.com/a/55581854/225217

cascade type save update in Hibernate

I am using hibernate with JPA annotations for relationship mapping.
I have three entities in my code User Group & User_Group
User & Group are in a ManyToMany relationship.
User_Group is a kinda bridge table but with some additional fields. So here is the modified mapping code.
User
#Entity
#Table(name = "USERS")
public class User {
#OneToMany(mappedBy = "user")
private Set<UserGroup> userGroups
}
Group
#Entity
#Table(name = "GROUPS")
public class Group {
#OneToMany(mappedBy = "group")
private Set<UserGroup> userGroups
}
UserGroup
#Entity
#Table(name = "USERS_GROUPS")
public class UserGroup {
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private User user;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "GROUP_ID")
private Group group;
}
When I set the user & group object to the usergroup & save it.
User user = new User("tommy", "ymmot", "tommy#gmail.com");
Group group = new Group("Coders");
UserGroup userGroup = new UserGroup();
userGroup.setGroup(group);
userGroup.setUser(user);
userGroup.setActivated(true);
userGroup.setRegisteredDate(new Date());
session.save(userGroup);
Things work fine. With CascadeType.ALL the group object & user object are updated too. But when I delete the userGroup object. The child object are deleted too.
Deletion of child objects is a strict no no.
There is no CascadeType.SAVE-UPDATE in JPA, which just does save or update but no delete. How do I achieve this.
If I remove the CascadeType.ALL from the mapping the child objects don't get updated & I need them to be updated.
SAVE_UPDATE is for save(), update(), and saveOrUpdate(), which are 3 Hibernate-proprietary methods. JPA only has persist() and merge(). So, if you want to use cascading on Hibernate-proprietary methods, you'll need to use Hibernate-proprietary annotations. In this case, Cascade.
Or you could stop using the Hibernate Session, and use the standard JPA API instead.
CascadeType.ALL includes CascadeType.REMOVE too.
The solution is to use all CascadeType.* you need except CascadeType.REMOVE, like so:
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}))
in your UserGroup definitions.
It's almost always a code smell when propagating from child to parent entity, it should be the other way round.
From Cascading best practices:
Cascading only makes sense only for Parent – Child associations (the
Parent entity state transition being cascaded to its Child entities).
Cascading from Child to Parent is not very useful and usually, it’s a
mapping code smell.
From Hibernate best practices:
Avoid cascade remove for huge relationships
Most developers (myself included) get a little nervous when they see a
CascadeType.REMOVE definition for a relationship. It tells Hibernate
to also delete the related entities when it deletes this one. There is
always the fear that the related entity also uses cascade remove for
some of its relationships and that Hibernate might delete more
database records than intended. During all the years I’ve worked with
Hibernate, this has never happened to me, and I don’t think it’s a
real issue. But cascade remove makes it incredibly hard to understand
what exactly happens if you delete an entity. And that’s something you
should always avoid. If you have a closer look at how Hibernate
deletes the related entities, you will find another reason to avoid
it. Hibernate performs 2 SQL statements for each related entity: 1
SELECT statement to fetch the entity from the database and 1 DELETE
statement to remove it. This might be OK, if there are only 1 or 2
related entities but creates performance issues if there are large
numbers of them.

Deciding type of fetch at runtime

I have an entity Application.java, which in turn has a property
#Audit(changeTracker = AttributeValueListChangeTracker.class)
#OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true, targetEntity = AttributeValue.class)
#OrderBy
#JoinColumn(name = "application_id")
#LazyCollection(LazyCollectionOption.FALSE)
private List<AttributeValue> attributeValueList = new ArrayList<AttributeValue>();
This eager fetching of this property is posing a problem in performance. I cannot make it lazy as in some cases eager fetch is required.
The case on which I am working doesn't require eager fetch.
is there a way to make this property load lazy just for my case?
You can write custom fetch method either via HQL or let's say Spring Data JPA which would not blindly go for whole entity (and it's eager relationships) but for certain properties which your case requires...

Hibernate List is empty when using lazy loading but it has results when eagerly loaded

I two entities a User and a Place witch are bound with many to many association.
When I try to get all the places for a given user thought the getter method, an emtpy list is returned but the user is bound to the place in the database and if I change the default fetching strategy to eager I can see all the places just fine.
I am using MySQL for the persistance.
The annotations used are:
for the User entity:
#ManyToMany
#JoinTable(name= "USER_PLACE",
joinColumns = {#JoinColumn(name="USER_ID")},
inverseJoinColumns = {#JoinColumn(name="PLACE_ID")})
private List<Place> places = new ArrayList<Place>();
and for the Place entity:
#ManyToMany(mappedBy = "places")
private List<User> users = new ArrayList<User>(0);
What can it be the cause of this?
To me, it looks like a Mapping issue in Your domain-model. Do the provided entities also map somewhere else? You might run into crazy joins with other tables. Could you provide all relevant entities? Also, the SQL statements generated by Hibernate for User.getPlaces() would be helpful.

Categories

Resources