Reputation: 77
The database table structure is the following:
id INT
extId VARCHAR
name VARCHAR
parent INT (references self.id)
Here is the entity
@Entity
@Table(name = "categories")
public class Category
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@ManyToOne
@JoinColumn(name = "parent", referencedColumnName = "id")
private Category parent;
@org.hibernate.annotations.OrderBy(clause = "name ASC")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", cascade = CascadeType.ALL)
private Set<Category> children = new HashSet<>();
@Column(name = "extId")
private String extId;
@Column(name = "name")
private String name;
public void addChild(Category child)
{
child.setParent(this);
this.children.add(child);
}
//getters and setters ...
}
In the very beginning there is only one entity:
{
id: 0
extId: ''
name: 'Category'
parent: null
children: Set<Category>{/*empty*/}
}
This entity is fetched in the beginning of program and assigned to another class
Later this class performs addition of new Category
as a child to existing root (the one that was fetched in the beginning) property
Addition of child is done like this:
Session session = HibernateSessionFactory.getInstance().getFactory().openSession();
//gather data
Category child = new Category();
//set name
//set extId
this.rootCategory.addChild(child);
Transaction tx = session.beginTransaction();
session.save(this.rootCategory);
tx.commit();
session.close();
After this instead of expected result in database:
Root(id(0), extId(''), parent(null), name('root'))
\-— Child(id(10), extId('art-0'), parent(0), name('child'))
I get the following result
Root(id(0), extId(''), parent(null), name('root'));
Root(id(10), extId(''), parent(null), name('root'))
\-— Child(id(11), extId('art-0'), parent(10), name('child'))
Notes:
Session
is created for each action and this session is acquired via Singleton SessionFactory
refresh()
root entity before adding a child -- everything is OK, no duplicatesWhat could be the reason of this behavior (assuming two different sessions)? And how can it be fixed?
Upvotes: 0
Views: 474
Reputation: 2801
After fetching from db at the beginning of your program, rootCategory
becomes a detached object.
Later when you want to use it in another session, you need to reattach it to this session. Instead of session.save()
, you can use session.update()
this.rootCategory.addChild(child);
Transaction tx = session.beginTransaction();
session.update(this.rootCategory);
tx.commit();
session.close();
Upvotes: 1
Reputation: 76
If you are closing the session after fetching rootCategory then the rootCategory object becomes a detached object according to the hibernate lifecycle and using Session.save() on it will create a new row for it. Therefore you either need to fetch, add the child and save the rootCategory object in the same session or use refresh to tell hibernate that it is not a new object but one that is already saved.
Upvotes: 1