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.
Related
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?).
I am working on an enterprise application where we use Hibernate and a many-to-many relationship with a join table. We are seeing very sporadic database deadlocks in production (with high volume) that we cannot recreate.
Category.java
public class Category {
....
private Set<Product> products = new HashSet<Product>();
...
}
Category.hbm.xml
<class
name="Category"
table="CATEGORY"
>
...
<!-- uni-directional many-to-many association to Product -->
<set
name="products"
table="CATEGORY_PRODUCT_ASSC"
lazy="false"
cascade="none"
>
<key column="CATEGORY_ID" />
<many-to-many class="Product" column="PRODUCT_ID" />
</set>
</class>
Product.java, Product.hbm.xml do not have a set of Categories, as this is uni-directional many-to-many
The CATEGORY_PRODUCT_ASSC table is a simple join table that only has 2 columns: CATEGORY_ID and PRODUCT_ID.
Right now, we are calling Session.saveOrUpdate on the Category instance object for the sole purpose of getting the inserts in the CATEGORY_PRODUCT_ASSC join table (nothing changed on the Category)
I turn on Hibernate show_sql and see the following:
update CATEGORY set NAME=?, DESCRIPTION=?, where category_id=?
insert into CATEGORY_PRODUCT_ASSC (CATEGORY_ID, PRODUCT_ID) values (?, ?)
The problem is that we have many products being created at the exact same second on multiple servers, all for the same Category.
When we see deadlocks, the update CATEGORY call is inevitably involved. We need to prevent these update CATEGORY SQL statements from being executed.
Option 1: Is there any way that I can call Session.saveOrUpdate(category) and have it not update Category (since that has not changed), but still do the insert into the join table CATEGORY_PRODUCT_ASSC ?
Option 2: If not, we have thought about just doing a straight INSERT of the CATEGORY_PRODUCT_ASSC rows via JDBC. However, one concern is stale Hibernate objects (Category objects) in the cache. Any ideas/recommendations on this possible approach?
Thank you very much in advance for your help. :-)
We resolved this issue. It did turn out to be the update category statement. Instead of using the CATEGORY_PRODUCT_ASSC table as a join-through for the many-to-many relationship, we created a Hibernate-managed entity that represents this join table ... CategoryProductAssc.
This way, we could directly persist the relationship without having to call Session.saveOrUpdate on the Category instance object for the sole purpose of getting the inserts in the CATEGORY_PRODUCT_ASSC join table when nothing changed on the Category object.
I created Cactus tests that spun up 20 simultaneous executions, tested old vs new code and our DBAs monitored and saw concurrency with the old code and no concurrency with the new code.
For example, I have the mapping file like this
<class name="my.test.model.Product" table="PRODUCT">
...
<set name="retailers" table="product_shop" lazy="false">
<key column="PRODUCT_ID" />
<many-to-many column="SHOP_ID" class="my.test.model.Shop" />
</set>
...
</class>
Now I want to query the Products of a particular Shop A. Something like this come to mind:
String searchHql = "select p from Product p inner join p.retailers retailing where p.retailers.shop_id = :shopId";
#SuppressWarnings("unchecked")
List<Product> productList = sessionFactory.getCurrentSession().createQuery(searchHql ).setInteger("shopId", shopId).list();
But it won't work. The error returned is:
could not resolve property: shop_id of: my.test.model.Shop. I have searched a lot, but still not find the right way to access the "many-to-many" subset in hql. Is this possible? Or I need to map the Product_Shop table to a model class?
UPDATE: as it seems there's no other way, I end up mapping Product_Shop into a class.
You're supposed to use the alias you assigned to the joined entity in the wgere clause:
select p from Product p inner join p.retailers retailing
where retailing.shop_id = :shopId
Side note: you should respect the Java naming conventions: shopId rather than shop_id.
Is there a way to tell Hibernate to wrap a column in a to_char when using it to join to another table or conversely convert a NUMBER to a VARCHAR? I have a situation where I have a table which contains a generic key column of type VARCHAR which stores the Id of another table which is a Number. I am getting a SQL exception when Hibernate executes the SQL it generates which uses '=' to compare the two columns.
Thanks...
P.S. I know this is not ideal but I am stuck with the schema so I have to deal with it.
This should be possible using a formula in your many-to-one. From section 5.1.22. Column and formula elements (solution also mentioned in this previous answer):
column and formula attributes can
even be combined within the same
property or association mapping to
express, for example, exotic join
conditions.
<many-to-one name="homeAddress" class="Address"
insert="false" update="false">
<column name="person_id" not-null="true" length="10"/>
<formula>'MAILING'</formula>
</many-to-one>
With annotations (if you are using Hibernate 3.5.0-Beta-2+, see HHH-4382):
#ManyToOne
#Formula(value="( select v_pipe_offerprice.offerprice_fk from v_pipe_offerprice where v_pipe_offerprice.id = id )")
public OfferPrice getOfferPrice() { return offerPrice; }
Or maybe check the #JoinColumnsOrFormula:
#ManyToOne
#JoinColumnsOrFormulas(
{ #JoinColumnOrFormula(formula=#JoinFormula(value="SUBSTR(product_idnf, 1, 3)", referencedColumnName="product_idnf")) })
#Fetch(FetchMode.JOIN)
private Product productFamily;
I have 2 tables:
orders: id
items: id, orderId, total, flag
I would like to make following query using Hibernate Criteria (DetachedCriteria):
SELECT
o.id,
SUM(i1.total),
SUM(i2.total)
FROM
orders o
LEFT JOIN
(
SELECT
i.orderId as orderId,
SUM(i.total) as total
FROM
items i
WHERE
i.flag = 0
GROUP BY
orderId
) AS i1
ON i1.orderId = o.id
LEFT JOIN
(
SELECT
i.orderId as orderId,
SUM(i.total) as total
FROM
items i
WHERE
i.flag = 1
GROUP BY
orderId
) AS i2
ON i2.orderId = o.id
GROUP BY
o.id
I know how to use DetachedCriteria to create subquery in WHERE clause, but as you can see, I need to do a subquery in FROM clause. If it is not possible, maybe there is a way to write it in SELECT clause (inside SUM()), because this query could be rewritten to such form.
I really need to use Criteria API even if I have to pass native SQL to the query.
I didn't show you classes or mapping, but as you can see, this is a very simple example.
I found solution for my problem. I had to make a POJO and mapping:
<class name="OrderTotal"
entity-name="OrderTotalForFlag0">
<subselect>
SELECT
i.orderId AS id,
SUM(i.total) AS total
FROM
items i
WHERE
i.flag = 0
GROUP BY
id
</subselect>
<id name="id" type="int" />
<property name="total" type="int" />
</class>
And of course for flag 1 it will be similar. This could be also done by declaring views in database and creating a mappings to that views. In this example I was using the same POJO class, but different entity-name.
Then I made a property in class Order and mapping:
<one-to-one name="orderTotalForFlag0" entity-name="OrderTotalForFlag0" />
<one-to-one name="orderTotalForFlag1" entity-name="OrderTotalForFlag1" />
Of course laziness could be set.
I'm pretty sure now, that this could be also done in different way - by making subquery in SELECT clause - using the formula attribute/element in mapping for properties, but this would work slower than subquery in FROM clause.
And of course all of that was in documentation to Hibernate ;)