Hibernate delete and update - java

I have a java object set to update. I used SaveOrUpdate method to do that.it works fine for updating children, but there is an issue with my requirement.
because I need to delete a child from database if one child is deleted.
please anyone have an good idea to implement this ?
Ex :-
project has a one to many relationship with people.
project has a atribute like,
class Project {
long id;
Set<People> people;
......
}
public void updateProject(Project project) {
try {
getCurrentSession().saveOrUpdate(project);
} catch (Exception ex) {
logger.error(ex);
}
project object contains people set but deleted some people Ids from that.
I need to update project with deleting unwanted people Ids
Thank you

I assume you have enabled cascading on your Project entity so my guess is that you need to add the orphanRemoval attribute to the relation.
Example for your case would be:
#OneToMany(cascade={CascadeType.ALL}, orphanRemoval=true)

Ref Code: Configure cascade with 'all-delete-orphan' for removing orphan data...
<hibernate-mapping>
<class name="User" table="UTABLE" >
<id name="UID" column="UID"/>
<property name="Name" column="F_Name"/>
<set name="phones" table="PHONE_NUMBERS" cascade="all-delete-orphan" lazy="true">
<key column="UID"/>
<one-to-many class="PhoneNumber" />
</set>
</class>
</hibernate-mapping>

Related

Econtainer null when loading EMF containment from Database using Hibernate

I have an EMF containment hierarchy: An House contains a list of Rooms, represented using an ecore file.
Before persisting, when I initially create my house and populate it with rooms, the eContainer value for a Room object correctly show the containing house. I then use Hibernate (no Teneo involved) to save the house (which cascade-saves the rooms).
When I reload the House object, I get references to all the Rooms. However, the eContainer value for a Room is now null. This is relevant because I use EcoreUtil.delete(bathroom) to delete a Room from its containing house, and that uses EObject.eContainer().
Relevant Hibernate Mapping:
<class name="House" table="house" lazy="false">
<bag name="rooms" lazy="true" cascade="save-update, delete">
<key update="true">
<column name="house_id" unique="false"/>
</key>
<one-to-many class="Room"/>
</bag>
</class>
<class name="Room" table="room" lazy="false">
</class>
What should I do to delete EMF objects? Should I call something other than EcoreUtil.delete(obj)? Should I manually add the eContainer references on load? Should I change my hibernate mapping?
Hibernate requires every property to have a getter and setter. In EMF (not using Teneo at least), there is a getter for Rooms but no setter.
public EList<Room> getRooms() {
if (rooms == null) {
rooms = new EObjectContainmentEList<Room>(Room.class, this, housePackage.HOUSE__ROOM);
}
return rooms;
}
I provided my own setter below.
public void setRooms(List<Room> roomList) {
this.rooms = new BasicEList<>();
this.rooms.addAll(roomList);
}
This was incorrect because a BasicEList does not do any provide EMF notification, so the eContainer was not getting set. I changed to the following, which in the underlying implementation uses a EObjectContainmentEList and so far it seems to work.
public void setRooms(List<Room> roomList) {
ECollections.setEList(getRooms(), roomList);
}

How to Create DB Context File in hibernate in java like Entity Framework c#

I have been working in .NET using Entity Framework with fluent API.
I created database context with all the relations of entities to map with tables and relations with entities with one to many etc.
I know the annotations way and mapping via XML files.
Following is the code in c#
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(u => u.DisplayName)
.HasColumnName("display_name");
}
}
Can any one tell me how to set a file in hibernate in JAVA to create the Blogs table for entity Blog and set properties for any entity with database rather then creating adding annotations.
Just some suggesions: Hibernate does not have the concept of Context but I usually insert a Context class where I set Hibernate Configuration class (one time for the project) and where I retrieve a session (Configuration.BuildSessionFactory() to get a ISessionFactory one time for the project and then ISessionFactory.OpenSession() or other methods similar to it). A session is the class where you start to build queries and insert/update/delete objects (so the usage is similar to the EF Context - you don't implement a Session like a DbContext -).
Usually you build the mapping using xml files like this
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="FiPlan.Data.Entities" assembly="FiPlan.Engine">
<class name="Account" table="Accounts" >
<id name="Id" column="ID" type="String" length="15" >
<generator class="assigned" />
</id>
<property name="Description" column="Description" type="String" not-null="false" length="50" />
</class>
</hibernate-mapping>
You add this files to the Configuration class (the one where you start to get a session).
Another consideration: there isn't the DbSet concept (every configured class can be accessed via queries).
I know that is not what you are looking for but I hope that this could be an help when you will start to read the Hibernate manual.
In short - I didnt find any way to create mapping or file like context for hibernate like in Entity Framework .NET

Hibernate mapping with one-to-many polymorphic relationship

I have the following class diagram and I want to map it to a database (note that Person has a list with objects of class Vehicle).
Also my database looks like:
All tables in the database that represent a subclass of the Vehicle class have all the fields of the superclass Vehicle. Also, all the relations show a one-to-many relationship from Person to Vehicle, Car and Motorcycle.
My hibernate mapping files are the following:
Person.hbm.xml
<hibernate-mapping package="....">
<class name="Person" table="Persons">
<id name="key" column="Person_ID">
<generator class="native"/>
</id>
<list name="ownedVehicles" inverse="false" cascade="all">
<key column="Person_ID" not-null="true" />
<list-index column="idx"/>
<one-to-many class="Vehicle"/>
</list>
</class>
</hibernate-mapping>
Vehicle.hbm.xml
<hibernate-mapping package="...">
<class name="Vehicle" table="Vehicles" polymorphism="implicit">
<id name="id" type="int" column="Vehicle_ID">
<generator class="increment"/>
</id>
<property name="numOfSeats"/>
<union-subclass name="Car" table="Cars"></union-subclass>
<union-subclass name="Motorcycle" table="Motorcycles"></union-subclass>
</class>
</hibernate-mapping>
The problem (error I get) is the following:
Hibernate: insert into Persons (Person_ID) values (default)
2013-06-26 15:41:52 WARN JdbcCoordinatorImpl:424 - HHH000386: ResultSet had no statement associated with it, but was not yet registered
Hibernate: update Car set numOfSeats=? where Vehicle_ID=?
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
I get this error when I run:
Car car = new Car();
car.setNumOfSeats(5);
Person person = new Person();
person.getOwnedVehicles().add(car);
ManagePerson managePerson = new ManagePerson();
Integer personID = managePerson.store(person);
The store() function of ManagePerson actually creates a session and a transaction and then uses the save() method provided by Hibernate to persist the objects into the database.
As far as I understand Hibernate usually will do insert into Persons, then insert into Cars and finally update Cars (the update is done to save the foreign keys on Cars table that will reference the Person that owns the cars). However, here this is not the case and the insert into Cars seems to be getting skipped. I understood how Hibernate works here by trying person.getOwnedVehicles().add(vehicle); instead of person.getOwnedVehicles().add(car); on the code given above.
As you might understand, I am trying to see if Hibernate actually understands in which "subclass" table a record should go, depending on the class of the object contained in the ownedVehicle list of the Person class. For example, if the ownedVehicles has an object of class Car and one of class Motorcycle, then each of these should go to Cars and Motorcycle tables respectively.
Note: I am using Hibernate 4.2.2 and HSQLDB 2.2.9.
I would appreciate any help with this.
Thanks.
I think it is just a matter of incorrect use of the implicit polymorphism of Hibernate.
Implicit polymorphism for your case can only work by changing your list to have
inverse="true". This can be done of course if your Vehicle class also 'knows' about the relationship with the Person class (e.g. by adding an 'Owner' property and the corresponding mapping).
(Have a look at this table and the case of "table per concrete-class (union-subclass)" and one-to-many associations.
If you enable logging and raise the log level to DEBUG you would see that currently Hibernate tries to update the Vehicles table with the Person_ID instead of the Car table like you meant it to. This is because of the inverse="true" and the limitations of the combination of the Table-per-concrete-class mapping strategy and implicit polymorphism (have a look at the documentation).
So, by having the Vehicle class know about its Owner and using inverse="true" you should be able to succeed in what you are trying to do. Either this or try one of the other inheritance mapping strategies (again have a look at the documentation).
If the managePerson.store(...) method doesn't have a recursive call to the objects in "getOwnedVehicles()" such that it can then call their "store" methods then you shouldn't expect that the created "car" object would be inserted into the table.
You are in fact calling "managePerson.store" not "manageCar.store", I'd have to see the code in the .store(...) method to be sure though but I would expect that it is not doing an iteration of the Vehicles and is not doing an insert for any discovered ones (why should it unless you built it explicitly to do that?).

Beginners Hibernate problem - simple mapping with non-simple exception!

Please help me with this hibernate problem, I'm new to hibernate and still trying to get my head around it. I can't seem to work this issue out. I imagine I'm missing something pretty simple.
I've followed the example here to achieve a many-to-one mapping, as my requirements are almost identical: http://www.coderanch.com/t/217519/ORM/java/Hibernate-Newbie-Many-Relation-Tutorial
Please note that when I try to persist the Picture object, the user variable is (at that point in time) empty, as is every other variable bar image.
Also note that I've set hibernate to generate the database schema by itself via config in the hibernate config file.
Here are my mapping files (declarations removed)
User.hbm.xml
<class name="msc.model.User" table="USER">
<id name="id" column="USER_ID">
<generator class="native"/>
</id>
<property name="username"/>
<property name="email"/>
<bag name="pictures"
table="PICTURE"
lazy="true"
cascade="save-update">
<key column="PICTURE_ID"/>
<one-to-many class="msc.model.Picture" />
</bag>
</class>
And Picture.hbm.xml
<class name="msc.model.Picture" table="PICTURE">
<id name="id" column="PICTURE_ID">
<generator class="native"/>
</id>
<property name="story"/>
<property name="tattooist"/>
<property name="pic"/>
<many-to-one name="user"
class="msc.model.User"
column="USER" />
<property name="image" type="blob">
<column name="IMAGE" not-null="true" />
</property>
</class>
The class files (getters and setters stripped)
Picture.java
package msc.model;
import java.io.File;
import java.sql.Blob;
public class Picture {
private Long id = null;
private User user = null;
private File pic = null;
private String story = null;
private String tattooist = null;
private Blob image = null;
}
User.java
package msc.model;
import java.util.ArrayList;
import java.util.List;
public class User {
private Long id = null;
private String username = null;
private String email = null;
private List<Picture> pictures = null;
}
The persistence code (note that bFile is byte stream created from a file):
Session hib_ses = HibernateUtil.getSessionFactory().getCurrentSession();
hib_ses.beginTransaction();
Picture picture = new Picture();
picture.setImage(Hibernate.createBlob(bFile));
Long id = (Long) hib_ses.save(picture);
hib_ses.getTransaction().commit();
Here is the exception:
Cannot add or update a child row: a foreign key constraint fails (`msc`.`picture`, CONSTRAINT `FK85BE8DE2885129D` FOREIGN KEY (`PICTURE_ID`) REFERENCES `user` (`USER_ID`))
Please help!
There is something very strange going on if that is the real error you get.
Cannot add or update a child row: a foreign key constraint fails (`msc`.`picture`, CONSTRAINT `FK85BE8DE2885129D` FOREIGN KEY (`PICTURE_ID`) REFERENCES `user` (`USER_ID`))
This says that PICTURE.PICTURE_ID is a reference to USER.USER_ID. But PICTURE_ID is the PK of picture, which Hibernate will generate upon insertion. Did you mean to create a constraint from PICTURE.USER to USER.USER_ID?
Oh, I see you wrote you generate the schema via Hibernate. I think the error is in your "bag" definition. The key column should not be PICTURE_ID, but USER.
It looks like you are trying to save the Picture before saving the User. Try saving the User first.
[edit]
From the mapping - it looks like there is a Parent/Child relationship between User and Picture.
There is a good example in the Hibernate Documentation for a Parent Child relationship.
If you want the User to be able to be null, then a uni-directional relationship would be better.
[edit]
Another good reference about mapping collections with Hibernate.

how to define an inverse cascade delete on a many-to-one mapping in hibernate

I have two classes A and B. Many B's can have association with a single A, hence a many-to-one relationship from B to A. I've mapped the relationship like:
<class name="A" table="tbl_A">
<property name="propA" column="colA"/>
</class>
<class name="B" table="tbl_B">
<property name="propB" column="colB"/>
<many-to-one name="a" class="A" column="col1" cascade="delete"/>
</class>
A has nothing mapped to B. Keeping this in mind we intend to delete B when it's associated A is deleted. This could have been possible if I could define an inverse="true" on the many-to-one association in B but hibernate does not allow that.
Can anyone help with this? We do not want to write anything in A for this.
Hibernate only cascades along the defined associations. If A knows nothing about Bs, nothing you do with A will affect Bs.
Pascal's suggestion is, therefore, the easiest way to do what you want:
<class name="A" table="tbl_A">
...
<set name="myBs" inverse="true" cascade="all,delete-orphan">
<key column="col1"/>
<one-to-many class="B"/>
</set>
</class>
<class name="B" table="tbl_B">
...
<many-to-one name="a" class="A" column="col1" not-null="true"/>
</class>
Note that setting cascade="delete" on B as you have it in your original code will NOT do what you want - it tells Hibernate to "delete A if B is deleted" which is likely to result in constraint violation (if there are any other Bs linked to that A).
If you absolutely cannot add a collection of Bs to A (though I can't really think of the circumstances where that'd be the case), your only other alternative is to define cascade delete from A to B at the foreign key level; your Bs will then be deleted when your A is deleted.
This is a rather ugly solution, however, because you have to be extremely careful of how you delete A in Hibernate:
Session must be flushed prior to deleting A (having pending updates to B may result in an error or A and some Bs being re-inserted behind the scenes)
All Bs linked to your A (and since you're not maintaining the relationship from A side that means all Bs) must be evicted from all active sessions and 2nd level cache.
I think you need to cascade="all,delete-orphan" from A to B's with a one-to-many association.

Categories