Simple object hierarchy with Hibernate - java

How to make hierarhical mapping Hibernate?
For example:
Category
id parent_id name
1 0 Root
2 1 Sub-root 1
3 1 Sub-root 2
4 2 Sub-(sub-root 1)
Is it possible to make lazy mapping for such Category object?

It is not exactly clear what you are asking.
However it would appear you are talking about a self-referencing relationship rather than Inheritance so you can then map as below. The default fetch strategy should be same as for any other #OneToMany i.e. LAZY.
#Entity
public class Category{
#Id
private Long id;
#ManyToOne
#JoinColumn(name = "parent_id")
private Category parent;
#OneToMany(mappedBy = "parent")
private Set<Category> subCategories;
}

I believe you want to ask about inheritance of entities. I recommend using JPA inheritance strategies. There are 3 available.
Single Table: Uses only one database table. columns need to be nullable and hence wastes database space
Joined Strategy: Uses multiple table which can be joined for insertion and retrieval of entity data. Saves database space but performance becomes an issue when inheritance hierarchy becomes wide and deep
Table per concrete class: Uses separate database tables which are not joined.
Different strategies have different advantages and disadvantages. You can choose according to your need.

Related

When we using relationship One To Many two side and when we using it one side

I have read some code describing relationship of two entities on both sides which look like following:
public class Department {
#OneToMany(mappedBy = "department",fetch = FetchType.EAGER , cascade = CascadeType.ALL)
private List<Course> courses = new ArrayList<>();
}
public class Course {
#ManyToOne
private Department department;
}
There are two scenarios: When I use relationship annotation on both sides("on both tables Department and Course ") with One-To-Many relationship and When i only use on one side("only table Derpartment). Scenario is similar for Many-To-Many relationship as well.
My question: Should "fetch = FetchType.EAGER , cascade = CascadeType.ALL" be defined only on one side or both sides in the above mentioned scenarios ?
fetch and cascade options can be defined on both sides. If its defined only on one side that it won't have any impact when the other side object is fetched. e.g. If eager fetch is set for courses in Department class but not in Course class then, if a select query is made on department then, it will fetch all its courses along with it But if a select query is made on course then, it won't fetch its associated department unless explicitly called out in query.
Same goes for cascade option. Thus, its definition on either side depends on the kind of queries which are required to be made. If there are going to be a lot of queries on department which needs all the courses information every time but its not the same for fetching a course then, fetch option should be defined only in Department class for courses.
Bi-directional association is good but with additional update in your code for efficient queries i.e. use JoinColumn with #ManyToOne association so that additional association mapping information between two entities doesn't have to be maintained on code side.

Hibernate #ManyToOne/#JoinColumn optimization

I have a Hibernate entity that is comprised of many other entities that are used within the application. The other entities that make up this MainEntity are joined by using #ManyToOne and #JoinColumn. This MainEntity class has 5 columns (#Column) and 7 #ManyToOne/#JoinColumn entities that are used.
I seem to be running into performance issues when retrieving all of these MainEntity classes. We want to serialize the MainEntity to JSON as well as the other entities that are associated with it. Note that there aren't that many that we are retrieving - less than 30 total.
Below is an example of what the class looks like along with my findAll() method to retrieve these classes. I know that #ManyToOne is EAGER by default, so I'm wondering if there's a better way to get all of these entities that is easier on the system. Thank you in advance.
#Entity(name = "MainEntity")
#Table(name = "main_entity")
public class MainEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
// Other #Columns defined here
#ManyToOne()
#JoinColumn(name = "entity_1_id")
private Entity1 entity1;
#ManyToOne()
#JoinColumn(name = "entity_2_id")
private Entity2 entity2;
#ManyToOne()
#JoinColumn(name = "entity_3_id")
private Entity3 entity3;
// ... and so on, for a total of 7 #ManyToOne() columns
}
Here is the findAll() method that I have:
final List<E> findAllOrdered(Class<E> clazz, Order order) {
final Session session = sessionManager.openNewSession();
try {
return session.createCriteria(clazz)
.addOrder(order)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
} finally {
sessionManager.closeSession(session);
}
}
I found myself having to add the Criteria.DISTINCT_ROOT_ENTITY because we were getting duplicate MainEntity results if a child had multiple associated with it. I suspect this is big part of my performance problem.
If you are retrieving unwanted response and if you want to filter then you may use #JsonIgnore
eg:
#ManyToOne()
#JoinColumn(name = "entity_1_id")
#JsonIgnore
private Entity1 entity1;
Few pointers to consider:
Consider making associations Lazy by default unless you really want to load all the association data and its associations along the parent.
Use JOIN in HQL/criteria based on which association we really want to fetch and the depth of associations.
Or use EntityGraph to decide which associations to be fetch.
Enable show_sql as this show the number of SQLs and the exact SQLs that are getting fired to the DB. This would be a good starting point and subsequently you can tune you associations to LAZY/EAGER, SELECT/JOIN/SUBSELECT based on your use case.
You can run these queries against the DB and see if tuning the query/DB (indexes, partitioning etc) will help reduce the query times.
See if second level cache would help for your use case. Note that second level cache will come with its own complexity and extra overhead and especially if the data is of transactional type and not read-only mostly. With application deployed on nodes maintaining the cache coherence will be another aspect to think about. Need to validate if the extra overhead and complexity is really worth the efficiency outcome of the second level cache.
From an application design perspective, you can also consider and see if you really want to retrieve the MainEntity and the associations in a single request or UI. Instead we could first show the MainEntity with some paging and based on the selection we could fetch the associations for that MainEntity with paging.
Note that, this is not a complete list. But a good starting point and based on your use case you can see which one would fit for you and any other additional techniques.

Hibernate Neo4j create relationships from one class

I am trying to use Hibernate to store family tree information. From what I have seen in the documentation, in order to connect two or more entities, they have to be from different classes. So, in order to create relationships between husband and wife, I would need to have two classes respectively. I think this is pointless because both classes would be identical (keep in mind that the tree can be quite large so I would have a lot of duplicate classes that way).
Is there a way to have a single class, for example Person and do the connections just from that class?
Also, if there is not way to achieve that, how would I connect siblings, for example
(p:Sibling)-[:SIBLING_OF]->(k:Sibling)
when they will both be from same class Sibling?
You can create relationships with entities of the same class the same way you create relationships with entities of different classes.
You can find an example of the mapping on the Hibernate OGM project sources:
https://github.com/hibernate/hibernate-ogm/blob/5.2.0.Alpha1/core/src/test/java/org/hibernate/ogm/backendtck/associations/recursive/TreeNode.java
and the realtive testcase:
https://github.com/hibernate/hibernate-ogm/blob/5.2.0.Alpha1/core/src/test/java/org/hibernate/ogm/backendtck/associations/recursive/RecursiveAssociationsTest.java
The tests map a tree structure with nodes having a parent node and many children, the mapping of the entity looks like like this:
#Entity
public class TreeNode {
#Id
private String name;
#ManyToOne
private TreeNode parent;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "parent",
cascade = CascadeType.ALL, orphanRemoval = true)
private List<TreeNode> children = new ArrayList<TreeNode>( 3 );
...
}
NOTE:
Based on your needs, you can create the association using native queries but I wouldn't recommend it. Hibernate OGM becomes unaware of the relationship and problems might occur.
You can use CYPHER query for creating relationship for same class entities
as follow
Match(u:sibling{name:'abc'}),Match(p:sibling{name:'xyz'})
CREATE (u)-[:SIBLING_OF]-(p)
executing CYPHER query can be found here

Hibernate: how to set relationship among three entity classes, their join table and save in database

I have following three entity classes.
#Entity
public class User {
#Id
#Column(nullable = false)
#GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
}
#Entity
public class LanguageProficiencyLevel {
#Id
#Column(nullable = false)
#GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name; // A1, A2, B1 ... etc
}
#Entity
public class Language {
#Id
#Column(nullable = false)
#GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name; //English, Chinese ect ...
}
Currently in the database, I have around 20 languages saved in Language table and 6 language proficiency levels A1, A2, B1, B2, C1, C2 saved in LanguageProficiencyLevel table.
Now I have the following relationship among the entity classes.
A User can know more than one languages with one proficiency level and A language with one proficiency level is known by many users.
So for example, A user may know English and his English proficiency may be C1, Again same user may also know Spanish and his Spanish proficiency may be B1.
Here I understand, User and Language has many to many relation. But I don't understand how to relate LanguageProficiencyLevel with User or Language.
Also how should I save this in database? My idea is to make one join table (LanguageSkill) with column names as user_id, language_id and languageProficiencyLevel_id and this table row will be inserted when a user is created. I am not sure if this the way to implement it. Please give me an idea how to do this and what should be the configuration for this.
User and Language will have many to many relation as you said. And, Language and LanguageProficiencyLevel will have one to one relation.
So, you have to create a mapping table that will have have many to one relation to all the 3 tables.
Refer this link to create mapping table with multiple columns.
Your relations between entity objects would be like:
A user can have multiple languages and language can have multiple users. So its a Many-to-Many relationship between User-Language.
A language can have only one proficiency at a time but a proficiency can have multiple languages. So LanguageProficiency to Language would be a one-to-many relation.
Relation between user and language proficiency is also many-to-many.
Here is a link how you can go about your database design for many-to-many relations.
How to implement a many-to-many relationship in PostgreSQL?
After creating the database design you can probably use some reverse engineering tool(https://www.javacodegeeks.com/2013/10/step-by-step-auto-code-generation-for-pojo-domain-java-classes-and-hbm-using-eclipse-hibernate-plugin.html) to create the hibernate pojo classes. I would recommend to use a tool to do this rather than taking things in hands to avoid unnecessary issues.
So now if you look carefully... your Entity classes of User, Language and LanguageProficiency would be something like this.
Hope this is useful.
You should absolutely create another table LanguageSkill, like you said.
Language and Proficiency are so-called base data - they will have comparatively few entries and will be independent of users. Neither of them should be mapped into User.
A User should then have a #OneToMany relation to LanguageSkill, which represents his knowledge of a particular language. LanguageSkill has a #ManyToOne to both Language and Proficiency (and User).
Skipping LanguageSkill would result in data duplication in your schema, or at least in a schema that is hard to read with all the jointables.
Also, it would mix concerns - data that is relatively stable (Language, Proficiency) and data that will change often (a person's knowledge of a language).

JPA update many-to-many deleting records

I have a #ManyToMany relationship between two entities. When I perform an update on the owning side, it appears that JPA deletes all the linked records from my database and re-inserts them. For me this is a problem because I have a MySQL trigger that fires before a record is deleted. Any ideas on how to get around this problem?
#Entity
public class User {
#Id
#Column(name="username")
private String username;
...
#ManyToMany
#JoinTable(name="groups", joinColumns=
#JoinColumn(name="username", referencedColumnName="username"),
inverseJoinColumns=#JoinColumn(name="groupname",
referencedColumnName="type_id"))
private List<UserType> types;
...
}
#Entity
public class UserType {
#Id
#Column(name="type_id")
private String id;
#ManyToMany(mappedBy="types")
private List<User> users;
...
}
Use Set instead of List solved the problem. But I have no idea why it works.
Another solution provided by Hibernate is to split the #ManyToMany association into two bidirectional #OneTo#Many relationships. See Hibernate 5.2 documentation for example.
If a bidirectional #OneToMany association performs better when
removing or changing the order of child elements, the #ManyToMany
relationship cannot benefit from such an optimization because the
foreign key side is not in control. To overcome this limitation, the
link table must be directly exposed and the #ManyToMany association
split into two bidirectional #OneToMany relationships.
Try this one:
1) change declaration to:
private List<UserType> types = new Vector<UserType>();
2) never call
user.setTypes(newTypesList)
3) only call
user.getTypes().add(...);
user.getTypes().remove(...);
Its probably related to this question. You have to ensure you have an appropriately defined hashCode an equals method in your mapped object so that Eclipselink can determine equality and thus determine that the existing objects map to existing objects in the DB. Otherwise it has no choice but to recreate the child objects every time.
Alternatively, I've read that this kind of join can only support efficient adding and removing of list items if you use an index column, but that's going to be EclipseLink specific, since the JPA annotations don't seem to support such a thing. I know there is an equivalent Hibernate annotation, but I don't know what it would be in Eclipselink, if such a thing exists.
It appears my problem was that I was not merging the entity.

Categories