Hibernate set mapped to a 'sql select' table - java

Good day,
I have a hibernate mapping which goes something like this
<class name="Person">
<id name="id" type="long" column="person_id" unsaved-value="null">
<generator class="sequence">
<param name="sequence">person_id_seq</param>
</generator>
</id>
...
<set name="thinCollection" table="(select person_id, person_property from some_other_table where another_property = 'something')" fetch="subselect" lazy="false">
<key column="person_id"/>
<element column="person_property" type="long"/>
</set>
...
</class>
Now my problem is, when a Person object gets flushed, it tries to execute a Collection Remove Action against Person#thinCollection, which fails because it's trying to execute delete from (select person_id, person_property from some_other_table where another_property = 'something').
Thus in line with that, how do I stop Hibernate from executing such actions (as well as update and inserts) ?
Thanks

I believe you want to use a subselect for your query, thus rendering it readonly.
http://docs.jboss.org/hibernate/stable/core/reference/en/html/mapping.html

Wouldn't
cascade="none"
Do the trick ?
[EDIT] Oups, thought it was NHibernate :P Well, I hope it would still work :)

What I currently did to solve this is to create my own persister (which is a subclass of BasicCollectionPersister) which never does an insertion/update/deletion.
But I am not sure if this is the best way to go about this or if could simply just add a magic mapping attribute to prevent the insertion/update/deletion.
[EDIT]
I found it hard to map my Set to a subselect so I used my own custom BasicCollectionPersister instead. I overriden #isRowDeleteEnabled() and #isRowInsertEnabled() to both always return false. And I overriden #doUpdateRows(..) to always return 0.

Related

Hibernate: How do I join a table with itself?

I have a problem joining a table. Actually I'm really lost on how to do it. I have this Hibernate table mapping.
<class name="Technology" table="TECHNOLOGIES">
<id name="technoId">
<column name="techno_id" />
<generator class="identity" />
</id>
<property name="description" type="java.lang.String">
<column name="description" />
</property>
<many-to-one name="parent" class="Technology" />
</class>
The column parent is related with the same table. An example of the table so you can understand me.
techno_id | description | parent
1------------"Java"----------null
2------------"Hibernate"------1
3------------"HQL"------------2
4------------".NET"----------null
5------------"NHibernate"----4
That's basically an example of the table, it doesn't have real data, it's just an example.
What I want to do is, in a method that receives a techno_id, run with Criteria or HQL, and that brings me a List of results with the children id's too.
For example, if I send to the method the "1" techno_id, it should bring me a List with the ids "1, 2, 3".
I hope I was as clear as possible and you can help me.
Thanks, and sorry for my english jaja.
You need to use join tag with inverse
<join table ="Technologies" inverse ="true" optional = "false">
<key column = "techno_id"/>
<many-to-one name="parent" class="Technology" />
</join>
There are two ways of doing it.
By Criteria :
1. For specific level fetching : e.g 3 level fetching(As per your example)
public Technology getAllChildrenTechnology(long parentID){
Crtieria criteria = session.createCriteria(Technology.class);
criteria.add(Restriction.eq("id",parentID));
criteria.setFetchMode("parent",FetchMode.JOIN);
criteria.setFetchMode("parent.parent",FetchMode.JOIN);
criteria.setResultTransformer(criteria.DISTINCT_ROOT_PROPERTY);
Technology techno = (Technology)criteria.uniqueResult();
return techno;
}
2. For N level Fetching : You need to create n level for loop.(Recursive loop using above).
By Lazy :
There is a feature in hibernate that allow us to fetch some joins without using criteria.
<many-to-one name="parent" class="Technology" lazy="false"/>
I believe this question is not really Hibernate specific. Even you are writing SQL, you have no easy way to get a node with all its descendant, without special handling in design.
Easiest way is to have each Technology contains List of child technologies (Bidirectional relationship). Then traverse Technology's children recursively.
If you need quick retrieval from persistence storage, you have to cater that in your design. One way is as described in an answer I wrote before for a similar question. https://stackoverflow.com/a/7524077/395202
This method is not that Hibernate friendly anyway (It still works, just need extra attentions)

java hibernate skip insert 'id' on insert

I have designed a table (in postgres) where 'id' column is autoincremented via its SEQUENCE entity.
But when I began use hibernate I met the problem .... due creating the insert statement, it use the follow statement
INSERT INTO mytable (id, name) VALUE (0, 'blablabla')
...
but I want it make somethink like that:
INSERT INTO mytable (name) VALUE ('blablabla')
... Postgres have to generate id automatically (at least when I ran such scripts withing sql editor, it worked)
I belive it can be configured, but I don't know how...
Here is my part of my .hbm.xml:
<hibernate-mapping>
<class name="com.cse.database.bean.Category" table="category">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="name" type="string">
<column name="name" length="100" not-null="true" unique="true" />
</property>
</class>
</hibernate-mapping>
When you specify a <generator>, you're telling Hibernate how to create the ID. assigned means your application is doing it (which you don't want). You can specify a Hibernate class or even an application class to do it, which you don't want either. identity means the database does it for you, which is what you want. In some databases you can use sequence (which will query the sequence generator to get the ID, then write the record), and Hibernate allows you to use native to specify the most applicable for your DB.
<id name="id" type="int">
<column name="id" />
<generator class="identity" />
</id>
apparently works in this case.
assigned means that you explicitely assign the ID of the entity, which is not the case. The problem with these auto-generated IDs in postgreSQL, AFAIK, is that it's not possible to get the last generated ID, and that Hibernate has no way to get the ID assigned to the entity after it has inserted it. You should not use an autogenerated ID in PostgreSQL.
Instead, let Hibernate use a sequence generator and assign the ID to the entity before inserting it:
#SequenceGenerator(name = "FOO_SEQ", sequenceName = "FOO_SEQ")
public class Foo {
#Id
#GeneratedValue(generator = "FOO_SEQ")
#Column(name = "FOO_ID")
private Long id;

Hibernate not updating (merging) object

I have tag object that is driving me crazy. I'm trying to update it and every time I do everything seems OK until I check the database and it is not updated.
I'm having all the logging turned on but I don't see anything out of the ordinary.
Even after I create brand new object and try to update (or merge it) right after, it will not show in database. It will create the new object but it will not update it.
Did anyone have similar problem and how did you solve it?
<hibernate-mapping package="com.package">
<class name="com.package.Tag" table="tags" lazy="false" mutable="false" >
<meta attribute="generated-class">com.package.generated.AbstractTag</meta>
<meta attribute="scope-class">public abstract</meta>
<cache usage="read-write"/>
<id name="id" type="long" column="tag_id">
<generator class="native"/>
</id>
<property name="name" type="string" column="name" unique="true"/>
<property name="itemCount" type="integer" column="itemCount"/>
</class>
</hibernate-mapping>
Watch out for mutable="false" it makes the object imutable by the application:
As specified here: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html
mutable (optional - defaults to true): specifies that instances of the class are (not) mutable. Immutable classes, mutable="false", cannot be updated or deleted by the application. This allows Hibernate to make some minor performance optimizations.
Removing mutable="false" from the hbm file fixed the problem.
Have you tried setting (and saving) the Tag on the item, instead of adding items to the Tag class?
So basically doing what is required by the database, first creating a Tag (without any reference to items) and then creating items (records) with references to the Tag.

Hibernate WrongClassException / Sets / Discriminators?

The problem looks like this:
A Product table. 3 joined-subclasses: DVD, CD, Book.
A Role table (composite id: NAME, ROLE, PRODUCT), and subclasses by discriminator column ROLE: actor, director, artist, author, etc.. which are mapped to Actor, Director, Artist, Author java classes; (pretty usual I guess) ...
A Book has authors, a CD artists, a DVD actors and directors - these are all modelled via set with a one-to-many relation pointing to the class of the items, e.g. Author, Director, Artist, etc.. which are just subclasses of Role (see 2.)
As long as a joined-subclass has only one such set (of people/roles), all works fine. But when it has two, like DVD, actors and directors, Hibernate throws a WrongClassException?
XML excerpt (Product.hbm.xml):
<joined-subclass name="media.DVD" table="V_DVD" lazy="false">
<key column="IDPRODUCT"/>
<property column="FORMAT" name="format" type="string"/>
...
<set name="actors" lazy="false">
<key column="IDPRODUCT"/>
<one-to-many class="media.DVD$Actor"/>
</set>
<set name="directors" lazy="false">
<key column="IDPRODUCT"/>
<one-to-many class="media.DVD$Director"/>
</set>
...
</joined-subclass>
XML (Person.hbm.xml):
<class name="media.Person" table="V_ROLE">
<composite-id>
<key-property column="NAME" name="name" type="string"/>
<key-property column="ROLE" name="role" type="string"/>
<key-many-to-one class="media.Product" column="IDPRODUCT"
name="product"/>
</composite-id>
<discriminator column="ROLE" insert="false" type="string"/>
<property name="name"/>
<property name="role"/>
<many-to-one class="media.Product" column="IDPRODUCT"
insert="false" name="product" update="false"/>
<subclass discriminator-value="author" name="media.Book$Author"/>
<subclass discriminator-value="artist" name="media.Music$Artist"/>
<subclass discriminator-value="creator" name="media.DVD$Creator"/>
<subclass discriminator-value="director" name="media.DVD$Director"/>
<subclass discriminator-value="actor" name="media.DVD$Actor"/>
</class>
It seems somewhat ok to me, yet it throws an exception.
Thank you for any idea!
I've got to say, this is a rather esoteric mapping. Why are you using a composite key (with discriminator being a part of it no less) instead of surrogate?
One possible issue here is you may be manually setting discriminator value (via role property) to something other than what it should be for given subclass. Hibernate won't be able to overwrite it (discriminator is mapped with insert="false") and this would cause a WrongClassException on subsequent select.
It's also possible that there' something funky going on in the Product mapping from which media.DVD extends and which you didn't include. Can you add that as well as provide full stack trace?
The problem is basically that your model is not normalized: You tell hibernate that there is a composite key, but you use only part of that key to reference the table.
I think you can implement this by either having a set of people in your product and each person has a role, or by mapping each set to a separate (linking) table with your person table.
Another more esoteric approach would be to map to a MultiMap: In fact you have a Map<Role, Set<Person>> in your product. Hibernate does not support this out of the box, but I once wrote a UserType for this.
Cheers,
-Maarten

Lazy One-to-One using Proxy not working

I've got a one-to-one relation between a dealer and a seller which should be lazy using a proxy. For the side on which the foreign key is defined (the seller, references the dealer), this works fine. But it doesn't work from the other side - the seller is always loaded eagerly. I set constrained="true" as described in "Some explanations on lazy loading", but that didn't help.
Following is the used mapping:
<class name="Role" table="PER_PERSROLE" abstract="true">
<id column="OID" type="long">
<generator class="native" />
</id>
<discriminator column="SUBTYPE" type="string" />
</class>
<subclass name="Dealer" extends="Role" discriminator-value="DEAL">
<property name="gpNr" column="GP_NR" type="string" />
<one-to-one name="seller" property-ref="dealer" lazy="proxy" constrained="true"
outer-join="false" />
</subclass>
<subclass name="Seller" extends="Role" discriminator-value="SELL">
<many-to-one name="dealer" column="SELLER_DEALEROID" lazy="proxy"
outer-join="false" />
</subclass>
Is it a problem that both classes reside in one table? I see that strictly speaking the relation isn't constrained on the database (it can't using this model), but the domain model always needs both entities and the application ensures this.
I think that the page you linked to explained it best, though I am not sure why it recommends setting constrained="true". If you think about it on the database level, Hibernate can't tell if the given property (the Dealer's seller) should be null or not without hitting the database (it needs to do a SELECT ... WHERE OID=:sellerOrDealerId to see if any rows are returned). And while it's hitting the database, it might as well fetch the rest of the row. From the other side of the association (Seller's dealer), there are no such problems since it has already fetched the row (and thus the SELLER_DEALEROID column).
I did encounter something similar to this once and was able to solve it by making the association non-optional (err, non-nullable)
I'm guessing you are loading session.get(id)? Have you tried load the instance using an HQL query? That will allow you to specify in the query which relationships to eager or lazy load.
HTH

Categories

Resources