Parent child relationship hibernate - java

I've been trying to recreate the parent/child scenario with hibernate, I used this as an example (very new to hibernate):
http://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/
My situation is similar to this. I am working on a project that has some task objects which should be part of some task flow object.
So there are two entities task and taskflow.
Taskflow should have many or at least one task.
There are already some tasks in the task table, now I want to insert some entries into taskflow table so that taskflow object has list or set of tasks.
Forgot to mention in my original question :
Task can be inside many different task flows
My taskflow looks something like :
class Taskflow{
int taskflowid;
String taskflowname;
List<Task> tasklist;
}
in the database taskflow has 2 fields taskflowid and taskflowname.
This is how Task looks like :
class Task{
//many properties/fields
}
Taking this example into consideration when compared to examples I googled, there is always some kind of relation from Task back to the TaskFlow. Is that necessary? I just want taskflow to have reference to task. Am I thinking this one all wrong?

If you don't declare relationship it would be simple member variables. In order to hibernate understand that you have one to many relationship you need to specify it in some for .hbm , annotation
#OneToMany //This for hibernate to understand that you have one to many relationship with Task
List<Task> tasklist;
inside Task
#ManyToOne
Taskflow taskFlow
Remember default names will be used to generate column names. Please refer tutorial over here

Hibernate supports relationships of different cardinality (one-to-one, one-to-many/many-to-one, many-to-many) and different directionality (unidirectional or bidirectional).
In your case you have a many-to-many relationship, which can be either unidirectional (if Task don't need to contain a collection of all TaskFlows it's a part of), or bidirectional.
For example, a unidirectional relatioship from TaskFlow to Task:
class Taskflow {
...
#ManyToMany
private List<Task> tasks;
...
}
See also:
Chapter 7. Collection mapping

Related

Cascade update ConstraintViolationException on compound UniqueConstraint

I'll simplify the example to get the idea across. My model looks like the following :
Projects have a ManyToMany relationship with Jobs. In order to create the join table, I created a ProjectJob entity that has an added column, "job_order". Project references an OneToMany link to a list of ProjectJob, with CascadeType.ALL.
I have a UniqueConstraint on ProjectJob that looks like this :
#UniqueConstraint(columnNames = {"project_id", "job_order"}
Everything works like a charm unless I want to reorder the jobs in the project. Basically, I flip the orders around in my service and made sure that every ProjectJob was a unique job_order in the list, and then save the Project (since the ProjectJobs will be cascaded). Problems arise when JPA/Hibernate tries to flush the transaction since it tries to update "row by row", and obviously the UniqueConstraint is violated after the first update (even though the whole batch of updates would give a coherent state).
Weirdly enough, the service call happens inside a transaction, so I'm not sure why I get this error.
Is there any way to update the child members of a collection in a unique statement so that the UniqueConstraint gets checked after all the children have been updated, instead of getting triggered after the first one? If not, what solution is available for my use case?
You could try to use deferred constraints. Or you use #ManyToMany #OrderColumn List<Job> jobs in Project instead which handles all of this automatically for you.

Saving an array of Entities in another entity with Hibernate

I have a Task entity that should contain an array of User entities in a #OneToMany relationship.
But I can't figure out a way to store said array without having a link table, since a User may be referenced in multiple Tasks.
The relationship should look like such, in TaskEntity:
#OneToMany(mappedBy = "user")
private Set<UserEntity> users = new HashSet<>(0);
What would be the proper way of doing it? How can a single row save an array of entities?
You can avoid join table (but it is not advised to do so, see below) for unidirectional one-to-many relationship. It would require foreign key to be on the target side of relationship(many side of relationship). You would need to specify a #JoinColumn annotation to point to the foreign key column.
#OneToMany
#JoinColumn(name="TASK_ID")
private Set<UserEntity> users = new HashSet<>(0);
It is not advisable, because of the following :
1) Performance : if both UserEntity state and Task states are changed, upon writing to UserEntity the FK to Task is not known, because UserEntity does not have reference to it. So in this case UserEntity might be written twice, once for UserEntity changes and once for Task changes.
2) Mapping : if UserEntity is assigned to a different task, and there is no reference back to Task from UserEntity, there will be no changes in context.
So it is advisable to go for Join Table in your case.
So a User can have many Tasks and each Task can have many Users.
Sounds like a classic fan-trap, you will need a link table and to use #ManyToMany.
However the Data-Structure should be modeled before looking into data access implementation.
What you have described is a Many to Many relationship, and your database structure should reflect that, before you think about how you can retrieve the data with Hibernate.

How to create different relationships with same entity in Neo4J/Spring?

I am using Spring Data Neo4J with Spring Boot v1.3.1. My Neo4J version is 2.1.6 .
Let's say, I have an Entity Person, which can have a relation named Friend with a Set of Person. So, I define a Set as one of the attributes of the Entity, use the #RelatedTo annotation and give it a type named Friend.
What if I want to have multiple other relationships, all with the same entity only, let's say, Enemy, Acquaintance etc. Do I have to define, separate attributes for all of them ? Can't I pass the relationship dynamically ?
For reference:
#NodeEntity
public class Person {
#RelatedTo(type="FRIEND", direction=Direction.BOTH)
public #Fetch Set<Person> friends;
//Do I have to do it like this ? This is odd.
#RelatedTo(type="ENEMY", direction=Direction.BOTH)
public #Fetch Set<Person> enemies;
//getter setters
}
EDIT 1-----------
Right now, I'm facing an issue with creating nodes in a bulk. Explaining the problem below :
After considering the approach suggested by Michael, here is what I have.
Basically, I have to create a lot of nodes in bulk. This node, Person will have an attribute with a unique index over it. Let's call it name. So, when the relations, Friend or Enemy are created, I want them to be created with person with unique name.
So, there will be two steps:
Create the Person nodes.(takes lot of time)
Create the relations between them.(does not take much time, around 30-40 ms)
I tried different approaches of creating nodes in bulk.
One approach was to commit the transactions after a certain number of nodes have been saved.
I had followed this link
I'm not sure about the performance improvement as calling the neo4jTemplate.save() still takes around 500ms.
From my logs:
Time taken to execute save:=612 ms
Time taken to execute save:=566 ms
Is this supposed to alright ?
Another approach was using Cypher, as suggested by Michael in his blog, here.
I used a Cypher query like this :
WITH [{name: "Person1", gravity: 1},
{name: "Person2", gravity: 2}] AS group
FOREACH (person IN group |
CREATE (e:Person {label: person.name, gravity: person.gravity}))
Issue with this approach is nodes do get created in bulk, but the unique index on name attribute is ignored. It seems, I must commit after saving each node.
So, is there any other way, in which I will be able to create nodes in bulk in a faster manner ?
You can handle it with creating relationship entities of the different types.
Or using Neo4jTemplate directly (createRelationshipBetween).
If you have such a dynamic setup, what would your entities look like?
You don't have to list the relationships in your entity. If they are dynamic you can also just have base attributes in your entities and access the relationships via a repository.

Load recursive object graph without N+1 Cartesian Product with JPA and Hibernate

When converting a project from Ibatis to JPA 2.1, I'm faced with a problem where I have to load a complete object graph for a set of objects, without hitting N+1 selects or using cartesian products for performance reasons.
A users query will yield a List<Task>, and I need to make sure that when I return the tasks, they have all properties populated, including parent, children, dependencies and properties. First let me explain the two entity objects involved.
A Task is part of a hierarchy. It can have a parent Task and it can also have children. A Task can be dependent on other tasks, expressed by the 'dependencies' property. A task can have many properties, expressed by the properties property.
The example objects have been simplified as much as possible and boilerplate code is removed.
#Entity
public class Task {
#Id
private Long id;
#ManyToOne(fetch = LAZY)
private Task parent;
#ManyToOne(fetch = LAZY)
private Task root;
#OneToMany(mappedBy = "task")
private List<TaskProperty> properties;
#ManyToMany
#JoinTable(name = "task_dependency", inverseJoinColumns = { #JoinColumn(name = "depends_on")})
private List<Task> dependencies;
#OneToMany(mappedBy = "parent")
private List<Task> children;
}
#Entity
public class TaskPropertyValue {
#Id
private Long id;
#ManyToOne(fetch = LAZY)
private Task task;
private String name;
private String value;
}
The Task hierarchy for a given task can be infinitely deep, so to make it easier to get the whole graph, a Task will have a pointer to it's root task via the 'root' property.
In Ibatis, I simply fetched all Tasks for the distinct list of root id's, and then did ad-hoc queries for all properties and dependencies with a "task_id IN ()" query. When I had those, I used Java code to add properties, children and dependencies to all model objects so that the graph was complete. For any size list of tasks, I would then only do 3 SQL queries, and I'm trying to do the same with JPA. Since the 'parent' property indicates where to add the children, I didn't even have to query for those.
I've tried different approaches, including:
Let lazy loading do it's job
Performance suicide, no need to elaborate :)
JOIN FETCH children, JOIN FETCH dependences, JOIN FETCH properties
This is problematic because the resulting cartesian products are huge, and my JPA implementation (Hibernate) doesn't support List, only Set when fetching multiple bags. A task can have a huge number of properties, making the cartesian products ineffective.
Ad-hoc queries the same way I did in ibatis
I cannot add children, dependencies and properties to the Lazy initialized collections on the Task objects, because Hibernate will then try to add them as new objects.
One possible solution could be to create new Task objects that are not managed by JPA and sew my hierarchy together using those, and I guess I can live with that, but it doesn't feel very "JPA", and then I couldn't use JPA for what it's good at - tracking and persisting changes to my objects automatically.
Any hints would be greatly appreciated. I'm open to using vendor spesific extensions if necessary. I'm running in Wildfly 8.1.0.Final (Java EE7 Full Profile) with Hibernate 4.3.5.Final.
Available options
There are some strategies to achieve your goals:
sub-select fetching would load all lazy entities with an additional sub-select, the very first time you need a lazy association of that given type. This sounds appealing at first, but it makes your app fragile to the number of additional sub-select entities to fetch and may propagate to other service methods.
batch fetching is easier to control since you can enforce the number of entities to be loaded in one batch and might not affect too much other use cases.
using a recursive common table expression if your DB supports it.
Plan ahead
In the end, it's all about what you plan on doing with the selected rows. If it's just about displaying them into a view, then a native query is more than enough.
If you need to retain the entities across multiple requests (first the view part, the second for the update part) then entities are a better approach.
From your response, I see you need to issue an EntityManager.merge() and probably rely on cascading to propagate children's state transitions (add/remove).
Since we are talking about 3 JPA queries, and as long as you don't get a Cartesian Product then you should be fine with JPA.
Conclusion
You should strive for the minimum amount of queries but it doesn't mean you will always have to have one and only one query. Two or three queries are not an issue at all.
As long as you control the query number and don't get into an N+1 query issue] you are fine with more than one query too. Trading a Cartesian Product (2 one-to-many fetches) for one join and one additional select is a good deal anyway.
In the end, you should always check the EXPLAIN ANALYZE query plan and reinforce/rethink your strategy.

JPA: locking over #ManyToMany-relationship

Following situation: Using EJB on Glassfish, I have two entity classes: A and B. They are linked by a #ManyToMany relationship so I have an additional table A_B.
Now I'd like to work on an instance of A, i.e. also change some relations to class B. More precisely, I alter values in A from time to time, later (and in a different invocation of a Bean's method from the client) I want to submit the changes.
Therefor, I thought of using an optimistic lock on A's instance. The problem is: as the #ManyToMany relationship is stored in table A_B, A's entry in the DB would not alter, the version field would not get incremented, so summarized that approach does not work for me.
Locking entities in A_B would not work either as in a #ManyToMany new rows could be inserted that affect my two classes. I'd need some kind of range-based lock to achieve that no links between my instances of A and B are altered, added or deleted. Unfortunately, I did not find a proper solution for that problem.
What would be the best way to lock entities of A including all relationships to other entities?

Categories