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?).
Related
I am trying to map a map collection of String, SuperClass using XML mapping files. Here's what I have:
<map name="mapName" cascade="all-delete-orphan">
<key column="ID" />
<index column="KEY" type="string" />
<one-to-many class="SuperClass" />
</map>
The SuperClass has (currently one but probably going to need some more in the future) a subclass that I'm going to call SubClass. So I have a bunch of SubClass and SuperClass objects in the map and when Hibernate attempts to search for them after adding them I get a
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
I'm pretty sure Hibernate is looking for classes of type SuperType when the objects in the map actually have some SubTypes as well.
Here's the gist of how the mapping was done for the hierarchy in case you need a better representation of what I'm talking about:
<class name="SuperClass" table="SUPER_CLASS">
...properties...
(contains some <component> tags as well if it matters)
<union-subclass name="SubClass" table="SUBCLASS">
...more properties...
</union-subclass>
</class>
Is it possible (and if yes, how?) to map entity class to be fetched from table, but inserted/updated/deleted through procedures, instead of doing INSERT/UPDATE/DELETE on this table?
Entity configuration is done via XML, and using classes/methods specific to Oracle is OK.
You can map custom SQL for create/update/delete operations since version 3.5.
If you want to map through regular SQL statements, you can just write SQL normally inside the <sql-insert>, <sql-update>, <sql-delete> elements.
When using stored procedures, you need to mark them as callable statements and use the call syntax. Note the required out parameters for delete and update, returning the amount of rows removed.
<class name="Person">
<id name="id">
<generator class="increment"/>
</id>
<property name="name" not-null="true"/>
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
</class>
I have a simple scenario in many places in my webapp - when showing a list of objects, I don't want to query ALL the details (ie child objects), but when I show the user a single object for them to edit, I DO want to query the entire object. So I let Hibernate default to lazy-fetching these child objects for getting the list, and want to override that with fetch = JOIN at runtime. I tried 2 methods, both of which should work but dont!
Here is my mapping file :
<hibernate-mapping>
<class name="User" table="User">
<id name="objectId" type="java.lang.Integer">
<column name="Object_ID" />
<generator class="identity" />
</id>
<many-to-one name="address" class="Address" cascade="save-update" >
<column name="Address_ID" not-null="true"/>
</many-to-one>
... other User properties ...
</hibernate-mapping>
First, I tried querying the default lazy User object, and then using Hibernate.initialize() to load the lazy child object :
User user = session.get(User.class, (Serializable) id);
if ( !Hibernate.isInitialized(user.getAddress()) )
Hibernate.initialize(user.getAddress());
}
Hibernate recognized that the child Address object wasnt loaded but initialize() STILL didn't load the Address. Why?
Next I tried a fetch-profile, by adding this to the Hibernate mapping file :
<fetch-profile name="returnEntireUser">
<fetch entity="User" association="address" style="join"/>
</fetch-profile>
And then using the code:
User u1 = session.get(User.class, (Serializable) id);
session.enableFetchProfile("returnEntireUser");
User u2 = session.get(User.class, (Serializable) id);
And both u1 and u2 objects are the same - both without the Address object filled in. I know Hibernate recognizes the fetch profile, but still doesnt do anything.
Can anyone figure out WHY these methods dont work and what I can do to get them to work
OK, I feel a little bit stupid. Both of the above methods DO actually work, however you will NOT see the results in an Eclipse debugger session. In another section of code I used Criteria and the
setFetchMode("field",FetchMode.JOIN);
method and in this case the debugger object DOES contain all the data, so I expected to see the full object in the debugger using the above strategies, but it didn't happen.
Also for ohers to note you cannot run test cases in the code back to back on the same object because of Hibernate caching the object. The debugger might or might not show anything meaningful.
A table Product represents two entities Parent and Child.There relationship is defined in a separate table, lest's say Relation_Table.
hbm for Product is very straightforward. It does not have any reference to Reference_Table. hbm for Relation_Table looks like this:
<class name="RelationMember" table="RELATION_TABLE" lazy="true">
<id column="relation_id" type="int"/>
<many-to-one name="parent" class="Product" column="pId"/>
<many-to-one name="child" class="Product" column="child_id"/>
</class>
How would I fetch all the children for a given pId of a parent?
Is it like first I will fetch list of child_id and then use that list to read all entities from Product table?
Wondering if Hibernate provide some ways of mapping child_id directly to fetch entities from Product table.
You did not inlclude your classes but in typical cases, JPQL query is like:
select child from Product child where child.parent.id in :pids;
but Hibernate will still translate it to 2 joins, Product x Relation_Table x Product again.
You can use native query to have only 1 join (Product x Relation_Table).
But since the joins will be index based joins, you can trust DB to run it fast and there is no need for this extra optimization.
I have two tables Item and Property and one item can have multiple properties. I have modeled it correctly (i think) in hibernate and when loading the ItemModel object, all the properties load properly.
The problem is when I am trying to delete properties and then save it, the properties just get added to the existing ones.
ItemModel m = ...;
m.getPropertySet().size() // returns 5 initially
m.getPropertySet().clear();
// some update function which adds properties
m.getPropertySet().size(); // returns 1
...currentSession().saveOrUpdate(m);
What happens is that now the database has 6 properties for that category instead of 1. What should I do to make this work?
The model for Item's mapping to properties looks something like this
<set name="propertySet" cascade="all">
<key column="item_id" not-null="true"/>
<one-to-many class="Property"/>
</set>
Use cascade="all-delete-orphan". See the first example in the reference guide for a walkthrough of relationships like this. Also, if this is a bidirectional one-to-many, then this side (the set) should be mapped with inverse="true" so that the relationship is determined solely based on the other side of the relationship.